exec: Change cpu_abort() argument to CPUState
[qemu/cris-port.git] / target-ppc / mmu_helper.c
blob845a7252b35dd08c51261a16a0161c51a22425c3
1 /*
2 * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
4 * Copyright (c) 2003-2007 Jocelyn Mayer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #include "cpu.h"
20 #include "helper.h"
21 #include "sysemu/kvm.h"
22 #include "kvm_ppc.h"
23 #include "mmu-hash64.h"
24 #include "mmu-hash32.h"
26 //#define DEBUG_MMU
27 //#define DEBUG_BATS
28 //#define DEBUG_SOFTWARE_TLB
29 //#define DUMP_PAGE_TABLES
30 //#define DEBUG_SOFTWARE_TLB
31 //#define FLUSH_ALL_TLBS
33 #ifdef DEBUG_MMU
34 # define LOG_MMU(...) qemu_log(__VA_ARGS__)
35 # define LOG_MMU_STATE(cpu) log_cpu_state((cpu), 0)
36 #else
37 # define LOG_MMU(...) do { } while (0)
38 # define LOG_MMU_STATE(cpu) do { } while (0)
39 #endif
41 #ifdef DEBUG_SOFTWARE_TLB
42 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
43 #else
44 # define LOG_SWTLB(...) do { } while (0)
45 #endif
47 #ifdef DEBUG_BATS
48 # define LOG_BATS(...) qemu_log(__VA_ARGS__)
49 #else
50 # define LOG_BATS(...) do { } while (0)
51 #endif
53 /*****************************************************************************/
54 /* PowerPC MMU emulation */
56 /* Context used internally during MMU translations */
57 typedef struct mmu_ctx_t mmu_ctx_t;
58 struct mmu_ctx_t {
59 hwaddr raddr; /* Real address */
60 hwaddr eaddr; /* Effective address */
61 int prot; /* Protection bits */
62 hwaddr hash[2]; /* Pagetable hash values */
63 target_ulong ptem; /* Virtual segment ID | API */
64 int key; /* Access key */
65 int nx; /* Non-execute area */
68 /* Common routines used by software and hardware TLBs emulation */
69 static inline int pte_is_valid(target_ulong pte0)
71 return pte0 & 0x80000000 ? 1 : 0;
74 static inline void pte_invalidate(target_ulong *pte0)
76 *pte0 &= ~0x80000000;
79 #define PTE_PTEM_MASK 0x7FFFFFBF
80 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
82 static int pp_check(int key, int pp, int nx)
84 int access;
86 /* Compute access rights */
87 access = 0;
88 if (key == 0) {
89 switch (pp) {
90 case 0x0:
91 case 0x1:
92 case 0x2:
93 access |= PAGE_WRITE;
94 /* No break here */
95 case 0x3:
96 access |= PAGE_READ;
97 break;
99 } else {
100 switch (pp) {
101 case 0x0:
102 access = 0;
103 break;
104 case 0x1:
105 case 0x3:
106 access = PAGE_READ;
107 break;
108 case 0x2:
109 access = PAGE_READ | PAGE_WRITE;
110 break;
113 if (nx == 0) {
114 access |= PAGE_EXEC;
117 return access;
120 static int check_prot(int prot, int rw, int access_type)
122 int ret;
124 if (access_type == ACCESS_CODE) {
125 if (prot & PAGE_EXEC) {
126 ret = 0;
127 } else {
128 ret = -2;
130 } else if (rw) {
131 if (prot & PAGE_WRITE) {
132 ret = 0;
133 } else {
134 ret = -2;
136 } else {
137 if (prot & PAGE_READ) {
138 ret = 0;
139 } else {
140 ret = -2;
144 return ret;
147 static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
148 target_ulong pte1, int h, int rw, int type)
150 target_ulong ptem, mmask;
151 int access, ret, pteh, ptev, pp;
153 ret = -1;
154 /* Check validity and table match */
155 ptev = pte_is_valid(pte0);
156 pteh = (pte0 >> 6) & 1;
157 if (ptev && h == pteh) {
158 /* Check vsid & api */
159 ptem = pte0 & PTE_PTEM_MASK;
160 mmask = PTE_CHECK_MASK;
161 pp = pte1 & 0x00000003;
162 if (ptem == ctx->ptem) {
163 if (ctx->raddr != (hwaddr)-1ULL) {
164 /* all matches should have equal RPN, WIMG & PP */
165 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
166 qemu_log("Bad RPN/WIMG/PP\n");
167 return -3;
170 /* Compute access rights */
171 access = pp_check(ctx->key, pp, ctx->nx);
172 /* Keep the matching PTE informations */
173 ctx->raddr = pte1;
174 ctx->prot = access;
175 ret = check_prot(ctx->prot, rw, type);
176 if (ret == 0) {
177 /* Access granted */
178 LOG_MMU("PTE access granted !\n");
179 } else {
180 /* Access right violation */
181 LOG_MMU("PTE access rejected\n");
186 return ret;
189 static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
190 int ret, int rw)
192 int store = 0;
194 /* Update page flags */
195 if (!(*pte1p & 0x00000100)) {
196 /* Update accessed flag */
197 *pte1p |= 0x00000100;
198 store = 1;
200 if (!(*pte1p & 0x00000080)) {
201 if (rw == 1 && ret == 0) {
202 /* Update changed flag */
203 *pte1p |= 0x00000080;
204 store = 1;
205 } else {
206 /* Force page fault for first write access */
207 ctx->prot &= ~PAGE_WRITE;
211 return store;
214 /* Software driven TLB helpers */
215 static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
216 int way, int is_code)
218 int nr;
220 /* Select TLB num in a way from address */
221 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
222 /* Select TLB way */
223 nr += env->tlb_per_way * way;
224 /* 6xx have separate TLBs for instructions and data */
225 if (is_code && env->id_tlbs == 1) {
226 nr += env->nb_tlb;
229 return nr;
232 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
234 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(env, 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 ppc6xx_tlb_t *tlb;
256 int way, nr;
258 /* Invalidate ITLB + DTLB, all ways */
259 for (way = 0; way < env->nb_ways; way++) {
260 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
261 tlb = &env->tlb.tlb6[nr];
262 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
263 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
264 env->nb_tlb, eaddr);
265 pte_invalidate(&tlb->pte0);
266 tlb_flush_page(env, tlb->EPN);
269 #else
270 /* XXX: PowerPC specification say this is valid as well */
271 ppc6xx_tlb_invalidate_all(env);
272 #endif
275 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
276 target_ulong eaddr, int is_code)
278 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
281 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
282 int is_code, target_ulong pte0, target_ulong pte1)
284 ppc6xx_tlb_t *tlb;
285 int nr;
287 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
288 tlb = &env->tlb.tlb6[nr];
289 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
290 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
291 /* Invalidate any pending reference in QEMU for this virtual address */
292 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
293 tlb->pte0 = pte0;
294 tlb->pte1 = pte1;
295 tlb->EPN = EPN;
296 /* Store last way for LRU mechanism */
297 env->last_way = way;
300 static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
301 target_ulong eaddr, int rw, int access_type)
303 ppc6xx_tlb_t *tlb;
304 int nr, best, way;
305 int ret;
307 best = -1;
308 ret = -1; /* No TLB found */
309 for (way = 0; way < env->nb_ways; way++) {
310 nr = ppc6xx_tlb_getnum(env, eaddr, way,
311 access_type == ACCESS_CODE ? 1 : 0);
312 tlb = &env->tlb.tlb6[nr];
313 /* This test "emulates" the PTE index match for hardware TLBs */
314 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
315 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
316 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
317 pte_is_valid(tlb->pte0) ? "valid" : "inval",
318 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
319 continue;
321 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
322 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
323 pte_is_valid(tlb->pte0) ? "valid" : "inval",
324 tlb->EPN, eaddr, tlb->pte1,
325 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
326 switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
327 case -3:
328 /* TLB inconsistency */
329 return -1;
330 case -2:
331 /* Access violation */
332 ret = -2;
333 best = nr;
334 break;
335 case -1:
336 default:
337 /* No match */
338 break;
339 case 0:
340 /* access granted */
341 /* XXX: we should go on looping to check all TLBs consistency
342 * but we can speed-up the whole thing as the
343 * result would be undefined if TLBs are not consistent.
345 ret = 0;
346 best = nr;
347 goto done;
350 if (best != -1) {
351 done:
352 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
353 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
354 /* Update page flags */
355 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
358 return ret;
361 /* Perform BAT hit & translation */
362 static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
363 int *validp, int *protp, target_ulong *BATu,
364 target_ulong *BATl)
366 target_ulong bl;
367 int pp, valid, prot;
369 bl = (*BATu & 0x00001FFC) << 15;
370 valid = 0;
371 prot = 0;
372 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
373 ((msr_pr != 0) && (*BATu & 0x00000001))) {
374 valid = 1;
375 pp = *BATl & 0x00000003;
376 if (pp != 0) {
377 prot = PAGE_READ | PAGE_EXEC;
378 if (pp == 0x2) {
379 prot |= PAGE_WRITE;
383 *blp = bl;
384 *validp = valid;
385 *protp = prot;
388 static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
389 target_ulong virtual, int rw, int type)
391 target_ulong *BATlt, *BATut, *BATu, *BATl;
392 target_ulong BEPIl, BEPIu, bl;
393 int i, valid, prot;
394 int ret = -1;
396 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
397 type == ACCESS_CODE ? 'I' : 'D', virtual);
398 switch (type) {
399 case ACCESS_CODE:
400 BATlt = env->IBAT[1];
401 BATut = env->IBAT[0];
402 break;
403 default:
404 BATlt = env->DBAT[1];
405 BATut = env->DBAT[0];
406 break;
408 for (i = 0; i < env->nb_BATs; i++) {
409 BATu = &BATut[i];
410 BATl = &BATlt[i];
411 BEPIu = *BATu & 0xF0000000;
412 BEPIl = *BATu & 0x0FFE0000;
413 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
414 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
415 " BATl " TARGET_FMT_lx "\n", __func__,
416 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
417 if ((virtual & 0xF0000000) == BEPIu &&
418 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
419 /* BAT matches */
420 if (valid != 0) {
421 /* Get physical address */
422 ctx->raddr = (*BATl & 0xF0000000) |
423 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
424 (virtual & 0x0001F000);
425 /* Compute access rights */
426 ctx->prot = prot;
427 ret = check_prot(ctx->prot, rw, type);
428 if (ret == 0) {
429 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
430 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
431 ctx->prot & PAGE_WRITE ? 'W' : '-');
433 break;
437 if (ret < 0) {
438 #if defined(DEBUG_BATS)
439 if (qemu_log_enabled()) {
440 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
441 for (i = 0; i < 4; i++) {
442 BATu = &BATut[i];
443 BATl = &BATlt[i];
444 BEPIu = *BATu & 0xF0000000;
445 BEPIl = *BATu & 0x0FFE0000;
446 bl = (*BATu & 0x00001FFC) << 15;
447 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
448 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
449 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
450 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
451 *BATu, *BATl, BEPIu, BEPIl, bl);
454 #endif
456 /* No hit */
457 return ret;
460 /* Perform segment based translation */
461 static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
462 target_ulong eaddr, int rw, int type)
464 hwaddr hash;
465 target_ulong vsid;
466 int ds, pr, target_page_bits;
467 int ret;
468 target_ulong sr, pgidx;
470 pr = msr_pr;
471 ctx->eaddr = eaddr;
473 sr = env->sr[eaddr >> 28];
474 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
475 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
476 ds = sr & 0x80000000 ? 1 : 0;
477 ctx->nx = sr & 0x10000000 ? 1 : 0;
478 vsid = sr & 0x00FFFFFF;
479 target_page_bits = TARGET_PAGE_BITS;
480 LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
481 TARGET_FMT_lx " lr=" TARGET_FMT_lx
482 " ir=%d dr=%d pr=%d %d t=%d\n",
483 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
484 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
485 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
486 hash = vsid ^ pgidx;
487 ctx->ptem = (vsid << 7) | (pgidx >> 10);
489 LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
490 ctx->key, ds, ctx->nx, vsid);
491 ret = -1;
492 if (!ds) {
493 /* Check if instruction fetch is allowed, if needed */
494 if (type != ACCESS_CODE || ctx->nx == 0) {
495 /* Page address translation */
496 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
497 " hash " TARGET_FMT_plx "\n",
498 env->htab_base, env->htab_mask, hash);
499 ctx->hash[0] = hash;
500 ctx->hash[1] = ~hash;
502 /* Initialize real address with an invalid value */
503 ctx->raddr = (hwaddr)-1ULL;
504 /* Software TLB search */
505 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
506 #if defined(DUMP_PAGE_TABLES)
507 if (qemu_log_enabled()) {
508 hwaddr curaddr;
509 uint32_t a0, a1, a2, a3;
511 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
512 "\n", sdr, mask + 0x80);
513 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
514 curaddr += 16) {
515 a0 = ldl_phys(curaddr);
516 a1 = ldl_phys(curaddr + 4);
517 a2 = ldl_phys(curaddr + 8);
518 a3 = ldl_phys(curaddr + 12);
519 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
520 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
521 curaddr, a0, a1, a2, a3);
525 #endif
526 } else {
527 LOG_MMU("No access allowed\n");
528 ret = -3;
530 } else {
531 target_ulong sr;
533 LOG_MMU("direct store...\n");
534 /* Direct-store segment : absolutely *BUGGY* for now */
536 /* Direct-store implies a 32-bit MMU.
537 * Check the Segment Register's bus unit ID (BUID).
539 sr = env->sr[eaddr >> 28];
540 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
541 /* Memory-forced I/O controller interface access */
542 /* If T=1 and BUID=x'07F', the 601 performs a memory access
543 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
545 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
546 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
547 return 0;
550 switch (type) {
551 case ACCESS_INT:
552 /* Integer load/store : only access allowed */
553 break;
554 case ACCESS_CODE:
555 /* No code fetch is allowed in direct-store areas */
556 return -4;
557 case ACCESS_FLOAT:
558 /* Floating point load/store */
559 return -4;
560 case ACCESS_RES:
561 /* lwarx, ldarx or srwcx. */
562 return -4;
563 case ACCESS_CACHE:
564 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
565 /* Should make the instruction do no-op.
566 * As it already do no-op, it's quite easy :-)
568 ctx->raddr = eaddr;
569 return 0;
570 case ACCESS_EXT:
571 /* eciwx or ecowx */
572 return -4;
573 default:
574 qemu_log("ERROR: instruction should not need "
575 "address translation\n");
576 return -4;
578 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
579 ctx->raddr = eaddr;
580 ret = 2;
581 } else {
582 ret = -2;
586 return ret;
589 /* Generic TLB check function for embedded PowerPC implementations */
590 static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
591 hwaddr *raddrp,
592 target_ulong address, uint32_t pid, int ext,
593 int i)
595 target_ulong mask;
597 /* Check valid flag */
598 if (!(tlb->prot & PAGE_VALID)) {
599 return -1;
601 mask = ~(tlb->size - 1);
602 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
603 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
604 mask, (uint32_t)tlb->PID, tlb->prot);
605 /* Check PID */
606 if (tlb->PID != 0 && tlb->PID != pid) {
607 return -1;
609 /* Check effective address */
610 if ((address & mask) != tlb->EPN) {
611 return -1;
613 *raddrp = (tlb->RPN & mask) | (address & ~mask);
614 if (ext) {
615 /* Extend the physical address to 36 bits */
616 *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
619 return 0;
622 /* Generic TLB search function for PowerPC embedded implementations */
623 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
624 uint32_t pid)
626 ppcemb_tlb_t *tlb;
627 hwaddr raddr;
628 int i, ret;
630 /* Default return value is no match */
631 ret = -1;
632 for (i = 0; i < env->nb_tlb; i++) {
633 tlb = &env->tlb.tlbe[i];
634 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
635 ret = i;
636 break;
640 return ret;
643 /* Helpers specific to PowerPC 40x implementations */
644 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
646 ppcemb_tlb_t *tlb;
647 int i;
649 for (i = 0; i < env->nb_tlb; i++) {
650 tlb = &env->tlb.tlbe[i];
651 tlb->prot &= ~PAGE_VALID;
653 tlb_flush(env, 1);
656 static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
657 target_ulong eaddr, uint32_t pid)
659 #if !defined(FLUSH_ALL_TLBS)
660 ppcemb_tlb_t *tlb;
661 hwaddr raddr;
662 target_ulong page, end;
663 int i;
665 for (i = 0; i < env->nb_tlb; i++) {
666 tlb = &env->tlb.tlbe[i];
667 if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
668 end = tlb->EPN + tlb->size;
669 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
670 tlb_flush_page(env, page);
672 tlb->prot &= ~PAGE_VALID;
673 break;
676 #else
677 ppc4xx_tlb_invalidate_all(env);
678 #endif
681 static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
682 target_ulong address, int rw,
683 int access_type)
685 ppcemb_tlb_t *tlb;
686 hwaddr raddr;
687 int i, ret, zsel, zpr, pr;
689 ret = -1;
690 raddr = (hwaddr)-1ULL;
691 pr = msr_pr;
692 for (i = 0; i < env->nb_tlb; i++) {
693 tlb = &env->tlb.tlbe[i];
694 if (ppcemb_tlb_check(env, tlb, &raddr, address,
695 env->spr[SPR_40x_PID], 0, i) < 0) {
696 continue;
698 zsel = (tlb->attr >> 4) & 0xF;
699 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
700 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
701 __func__, i, zsel, zpr, rw, tlb->attr);
702 /* Check execute enable bit */
703 switch (zpr) {
704 case 0x2:
705 if (pr != 0) {
706 goto check_perms;
708 /* No break here */
709 case 0x3:
710 /* All accesses granted */
711 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
712 ret = 0;
713 break;
714 case 0x0:
715 if (pr != 0) {
716 /* Raise Zone protection fault. */
717 env->spr[SPR_40x_ESR] = 1 << 22;
718 ctx->prot = 0;
719 ret = -2;
720 break;
722 /* No break here */
723 case 0x1:
724 check_perms:
725 /* Check from TLB entry */
726 ctx->prot = tlb->prot;
727 ret = check_prot(ctx->prot, rw, access_type);
728 if (ret == -2) {
729 env->spr[SPR_40x_ESR] = 0;
731 break;
733 if (ret >= 0) {
734 ctx->raddr = raddr;
735 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
736 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
737 ret);
738 return 0;
741 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
742 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
744 return ret;
747 void store_40x_sler(CPUPPCState *env, uint32_t val)
749 PowerPCCPU *cpu = ppc_env_get_cpu(env);
751 /* XXX: TO BE FIXED */
752 if (val != 0x00000000) {
753 cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
755 env->spr[SPR_405_SLER] = val;
758 static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
759 hwaddr *raddr, int *prot,
760 target_ulong address, int rw,
761 int access_type, int i)
763 int ret, prot2;
765 if (ppcemb_tlb_check(env, tlb, raddr, address,
766 env->spr[SPR_BOOKE_PID],
767 !env->nb_pids, i) >= 0) {
768 goto found_tlb;
771 if (env->spr[SPR_BOOKE_PID1] &&
772 ppcemb_tlb_check(env, tlb, raddr, address,
773 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
774 goto found_tlb;
777 if (env->spr[SPR_BOOKE_PID2] &&
778 ppcemb_tlb_check(env, tlb, raddr, address,
779 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
780 goto found_tlb;
783 LOG_SWTLB("%s: TLB entry not found\n", __func__);
784 return -1;
786 found_tlb:
788 if (msr_pr != 0) {
789 prot2 = tlb->prot & 0xF;
790 } else {
791 prot2 = (tlb->prot >> 4) & 0xF;
794 /* Check the address space */
795 if (access_type == ACCESS_CODE) {
796 if (msr_ir != (tlb->attr & 1)) {
797 LOG_SWTLB("%s: AS doesn't match\n", __func__);
798 return -1;
801 *prot = prot2;
802 if (prot2 & PAGE_EXEC) {
803 LOG_SWTLB("%s: good TLB!\n", __func__);
804 return 0;
807 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
808 ret = -3;
809 } else {
810 if (msr_dr != (tlb->attr & 1)) {
811 LOG_SWTLB("%s: AS doesn't match\n", __func__);
812 return -1;
815 *prot = prot2;
816 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
817 LOG_SWTLB("%s: found TLB!\n", __func__);
818 return 0;
821 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
822 ret = -2;
825 return ret;
828 static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
829 target_ulong address, int rw,
830 int access_type)
832 ppcemb_tlb_t *tlb;
833 hwaddr raddr;
834 int i, ret;
836 ret = -1;
837 raddr = (hwaddr)-1ULL;
838 for (i = 0; i < env->nb_tlb; i++) {
839 tlb = &env->tlb.tlbe[i];
840 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
841 access_type, i);
842 if (!ret) {
843 break;
847 if (ret >= 0) {
848 ctx->raddr = raddr;
849 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
850 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
851 ret);
852 } else {
853 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
854 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
857 return ret;
860 static void booke206_flush_tlb(CPUPPCState *env, int flags,
861 const int check_iprot)
863 int tlb_size;
864 int i, j;
865 ppcmas_tlb_t *tlb = env->tlb.tlbm;
867 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
868 if (flags & (1 << i)) {
869 tlb_size = booke206_tlb_size(env, i);
870 for (j = 0; j < tlb_size; j++) {
871 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
872 tlb[j].mas1 &= ~MAS1_VALID;
876 tlb += booke206_tlb_size(env, i);
879 tlb_flush(env, 1);
882 static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
883 ppcmas_tlb_t *tlb)
885 int tlbm_size;
887 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
889 return 1024ULL << tlbm_size;
892 /* TLB check function for MAS based SoftTLBs */
893 static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
894 hwaddr *raddrp,
895 target_ulong address, uint32_t pid)
897 target_ulong mask;
898 uint32_t tlb_pid;
900 /* Check valid flag */
901 if (!(tlb->mas1 & MAS1_VALID)) {
902 return -1;
905 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
906 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
907 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
908 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
909 tlb->mas8);
911 /* Check PID */
912 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
913 if (tlb_pid != 0 && tlb_pid != pid) {
914 return -1;
917 /* Check effective address */
918 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
919 return -1;
922 if (raddrp) {
923 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
926 return 0;
929 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
930 hwaddr *raddr, int *prot,
931 target_ulong address, int rw,
932 int access_type)
934 int ret;
935 int prot2 = 0;
937 if (ppcmas_tlb_check(env, tlb, raddr, address,
938 env->spr[SPR_BOOKE_PID]) >= 0) {
939 goto found_tlb;
942 if (env->spr[SPR_BOOKE_PID1] &&
943 ppcmas_tlb_check(env, tlb, raddr, address,
944 env->spr[SPR_BOOKE_PID1]) >= 0) {
945 goto found_tlb;
948 if (env->spr[SPR_BOOKE_PID2] &&
949 ppcmas_tlb_check(env, tlb, raddr, address,
950 env->spr[SPR_BOOKE_PID2]) >= 0) {
951 goto found_tlb;
954 LOG_SWTLB("%s: TLB entry not found\n", __func__);
955 return -1;
957 found_tlb:
959 if (msr_pr != 0) {
960 if (tlb->mas7_3 & MAS3_UR) {
961 prot2 |= PAGE_READ;
963 if (tlb->mas7_3 & MAS3_UW) {
964 prot2 |= PAGE_WRITE;
966 if (tlb->mas7_3 & MAS3_UX) {
967 prot2 |= PAGE_EXEC;
969 } else {
970 if (tlb->mas7_3 & MAS3_SR) {
971 prot2 |= PAGE_READ;
973 if (tlb->mas7_3 & MAS3_SW) {
974 prot2 |= PAGE_WRITE;
976 if (tlb->mas7_3 & MAS3_SX) {
977 prot2 |= PAGE_EXEC;
981 /* Check the address space and permissions */
982 if (access_type == ACCESS_CODE) {
983 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
984 LOG_SWTLB("%s: AS doesn't match\n", __func__);
985 return -1;
988 *prot = prot2;
989 if (prot2 & PAGE_EXEC) {
990 LOG_SWTLB("%s: good TLB!\n", __func__);
991 return 0;
994 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
995 ret = -3;
996 } else {
997 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
998 LOG_SWTLB("%s: AS doesn't match\n", __func__);
999 return -1;
1002 *prot = prot2;
1003 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
1004 LOG_SWTLB("%s: found TLB!\n", __func__);
1005 return 0;
1008 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1009 ret = -2;
1012 return ret;
1015 static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1016 target_ulong address, int rw,
1017 int access_type)
1019 ppcmas_tlb_t *tlb;
1020 hwaddr raddr;
1021 int i, j, ret;
1023 ret = -1;
1024 raddr = (hwaddr)-1ULL;
1026 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1027 int ways = booke206_tlb_ways(env, i);
1029 for (j = 0; j < ways; j++) {
1030 tlb = booke206_get_tlbm(env, i, address, j);
1031 if (!tlb) {
1032 continue;
1034 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1035 rw, access_type);
1036 if (ret != -1) {
1037 goto found_tlb;
1042 found_tlb:
1044 if (ret >= 0) {
1045 ctx->raddr = raddr;
1046 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1047 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1048 ret);
1049 } else {
1050 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1051 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1054 return ret;
1057 static const char *book3e_tsize_to_str[32] = {
1058 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1059 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1060 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1061 "1T", "2T"
1064 static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1065 CPUPPCState *env)
1067 ppcemb_tlb_t *entry;
1068 int i;
1070 if (kvm_enabled() && !env->kvm_sw_tlb) {
1071 cpu_fprintf(f, "Cannot access KVM TLB\n");
1072 return;
1075 cpu_fprintf(f, "\nTLB:\n");
1076 cpu_fprintf(f, "Effective Physical Size PID Prot "
1077 "Attr\n");
1079 entry = &env->tlb.tlbe[0];
1080 for (i = 0; i < env->nb_tlb; i++, entry++) {
1081 hwaddr ea, pa;
1082 target_ulong mask;
1083 uint64_t size = (uint64_t)entry->size;
1084 char size_buf[20];
1086 /* Check valid flag */
1087 if (!(entry->prot & PAGE_VALID)) {
1088 continue;
1091 mask = ~(entry->size - 1);
1092 ea = entry->EPN & mask;
1093 pa = entry->RPN & mask;
1094 /* Extend the physical address to 36 bits */
1095 pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1096 size /= 1024;
1097 if (size >= 1024) {
1098 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1099 } else {
1100 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1102 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1103 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1104 entry->prot, entry->attr);
1109 static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1110 CPUPPCState *env, int tlbn, int offset,
1111 int tlbsize)
1113 ppcmas_tlb_t *entry;
1114 int i;
1116 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1117 cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
1118 " URWX WIMGE U0123\n");
1120 entry = &env->tlb.tlbm[offset];
1121 for (i = 0; i < tlbsize; i++, entry++) {
1122 hwaddr ea, pa, size;
1123 int tsize;
1125 if (!(entry->mas1 & MAS1_VALID)) {
1126 continue;
1129 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1130 size = 1024ULL << tsize;
1131 ea = entry->mas2 & ~(size - 1);
1132 pa = entry->mas7_3 & ~(size - 1);
1134 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1135 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1136 (uint64_t)ea, (uint64_t)pa,
1137 book3e_tsize_to_str[tsize],
1138 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1139 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1140 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1141 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1142 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1143 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1144 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1145 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1146 entry->mas2 & MAS2_W ? 'W' : '-',
1147 entry->mas2 & MAS2_I ? 'I' : '-',
1148 entry->mas2 & MAS2_M ? 'M' : '-',
1149 entry->mas2 & MAS2_G ? 'G' : '-',
1150 entry->mas2 & MAS2_E ? 'E' : '-',
1151 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1152 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1153 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1154 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1158 static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1159 CPUPPCState *env)
1161 int offset = 0;
1162 int i;
1164 if (kvm_enabled() && !env->kvm_sw_tlb) {
1165 cpu_fprintf(f, "Cannot access KVM TLB\n");
1166 return;
1169 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1170 int size = booke206_tlb_size(env, i);
1172 if (size == 0) {
1173 continue;
1176 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1177 offset += size;
1181 static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
1182 CPUPPCState *env, int type)
1184 target_ulong *BATlt, *BATut, *BATu, *BATl;
1185 target_ulong BEPIl, BEPIu, bl;
1186 int i;
1188 switch (type) {
1189 case ACCESS_CODE:
1190 BATlt = env->IBAT[1];
1191 BATut = env->IBAT[0];
1192 break;
1193 default:
1194 BATlt = env->DBAT[1];
1195 BATut = env->DBAT[0];
1196 break;
1199 for (i = 0; i < env->nb_BATs; i++) {
1200 BATu = &BATut[i];
1201 BATl = &BATlt[i];
1202 BEPIu = *BATu & 0xF0000000;
1203 BEPIl = *BATu & 0x0FFE0000;
1204 bl = (*BATu & 0x00001FFC) << 15;
1205 cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx
1206 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
1207 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
1208 type == ACCESS_CODE ? "code" : "data", i,
1209 *BATu, *BATl, BEPIu, BEPIl, bl);
1213 static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1214 CPUPPCState *env)
1216 ppc6xx_tlb_t *tlb;
1217 target_ulong sr;
1218 int type, way, entry, i;
1220 cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
1221 cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
1223 cpu_fprintf(f, "\nSegment registers:\n");
1224 for (i = 0; i < 32; i++) {
1225 sr = env->sr[i];
1226 if (sr & 0x80000000) {
1227 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1228 "CNTLR_SPEC=0x%05x\n", i,
1229 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1230 sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
1231 (uint32_t)(sr & 0xFFFFF));
1232 } else {
1233 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
1234 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1235 sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
1236 (uint32_t)(sr & 0x00FFFFFF));
1240 cpu_fprintf(f, "\nBATs:\n");
1241 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT);
1242 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE);
1244 if (env->id_tlbs != 1) {
1245 cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB"
1246 " for code and data\n");
1249 cpu_fprintf(f, "\nTLBs [EPN EPN + SIZE]\n");
1251 for (type = 0; type < 2; type++) {
1252 for (way = 0; way < env->nb_ways; way++) {
1253 for (entry = env->nb_tlb * type + env->tlb_per_way * way;
1254 entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
1255 entry++) {
1257 tlb = &env->tlb.tlb6[entry];
1258 cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s ["
1259 TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
1260 type ? "code" : "data", entry % env->nb_tlb,
1261 env->nb_tlb, way,
1262 pte_is_valid(tlb->pte0) ? "valid" : "inval",
1263 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
1269 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1271 switch (env->mmu_model) {
1272 case POWERPC_MMU_BOOKE:
1273 mmubooke_dump_mmu(f, cpu_fprintf, env);
1274 break;
1275 case POWERPC_MMU_BOOKE206:
1276 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1277 break;
1278 case POWERPC_MMU_SOFT_6xx:
1279 case POWERPC_MMU_SOFT_74xx:
1280 mmu6xx_dump_mmu(f, cpu_fprintf, env);
1281 break;
1282 #if defined(TARGET_PPC64)
1283 case POWERPC_MMU_64B:
1284 case POWERPC_MMU_2_06:
1285 case POWERPC_MMU_2_06a:
1286 case POWERPC_MMU_2_06d:
1287 dump_slb(f, cpu_fprintf, env);
1288 break;
1289 #endif
1290 default:
1291 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1295 static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1296 target_ulong eaddr, int rw)
1298 int in_plb, ret;
1300 ctx->raddr = eaddr;
1301 ctx->prot = PAGE_READ | PAGE_EXEC;
1302 ret = 0;
1303 switch (env->mmu_model) {
1304 case POWERPC_MMU_SOFT_6xx:
1305 case POWERPC_MMU_SOFT_74xx:
1306 case POWERPC_MMU_SOFT_4xx:
1307 case POWERPC_MMU_REAL:
1308 case POWERPC_MMU_BOOKE:
1309 ctx->prot |= PAGE_WRITE;
1310 break;
1312 case POWERPC_MMU_SOFT_4xx_Z:
1313 if (unlikely(msr_pe != 0)) {
1314 /* 403 family add some particular protections,
1315 * using PBL/PBU registers for accesses with no translation.
1317 in_plb =
1318 /* Check PLB validity */
1319 (env->pb[0] < env->pb[1] &&
1320 /* and address in plb area */
1321 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1322 (env->pb[2] < env->pb[3] &&
1323 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1324 if (in_plb ^ msr_px) {
1325 /* Access in protected area */
1326 if (rw == 1) {
1327 /* Access is not allowed */
1328 ret = -2;
1330 } else {
1331 /* Read-write access is allowed */
1332 ctx->prot |= PAGE_WRITE;
1335 break;
1337 default:
1338 /* Caller's checks mean we should never get here for other models */
1339 abort();
1340 return -1;
1343 return ret;
1346 static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1347 target_ulong eaddr, int rw, int access_type)
1349 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1350 int ret = -1;
1351 bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1352 || (access_type != ACCESS_CODE && msr_dr == 0);
1354 #if 0
1355 qemu_log("%s\n", __func__);
1356 #endif
1358 switch (env->mmu_model) {
1359 case POWERPC_MMU_SOFT_6xx:
1360 case POWERPC_MMU_SOFT_74xx:
1361 if (real_mode) {
1362 ret = check_physical(env, ctx, eaddr, rw);
1363 } else {
1364 /* Try to find a BAT */
1365 if (env->nb_BATs != 0) {
1366 ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
1368 if (ret < 0) {
1369 /* We didn't match any BAT entry or don't have BATs */
1370 ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1373 break;
1375 case POWERPC_MMU_SOFT_4xx:
1376 case POWERPC_MMU_SOFT_4xx_Z:
1377 if (real_mode) {
1378 ret = check_physical(env, ctx, eaddr, rw);
1379 } else {
1380 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1381 rw, access_type);
1383 break;
1384 case POWERPC_MMU_BOOKE:
1385 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1386 rw, access_type);
1387 break;
1388 case POWERPC_MMU_BOOKE206:
1389 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1390 access_type);
1391 break;
1392 case POWERPC_MMU_MPC8xx:
1393 /* XXX: TODO */
1394 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1395 break;
1396 case POWERPC_MMU_REAL:
1397 if (real_mode) {
1398 ret = check_physical(env, ctx, eaddr, rw);
1399 } else {
1400 cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n");
1402 return -1;
1403 default:
1404 cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
1405 return -1;
1407 #if 0
1408 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1409 __func__, eaddr, ret, ctx->raddr);
1410 #endif
1412 return ret;
1415 hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
1417 PowerPCCPU *cpu = POWERPC_CPU(cs);
1418 CPUPPCState *env = &cpu->env;
1419 mmu_ctx_t ctx;
1421 switch (env->mmu_model) {
1422 #if defined(TARGET_PPC64)
1423 case POWERPC_MMU_64B:
1424 case POWERPC_MMU_2_06:
1425 case POWERPC_MMU_2_06a:
1426 case POWERPC_MMU_2_06d:
1427 return ppc_hash64_get_phys_page_debug(env, addr);
1428 #endif
1430 case POWERPC_MMU_32B:
1431 case POWERPC_MMU_601:
1432 return ppc_hash32_get_phys_page_debug(env, addr);
1434 default:
1438 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1440 /* Some MMUs have separate TLBs for code and data. If we only try an
1441 * ACCESS_INT, we may not be able to read instructions mapped by code
1442 * TLBs, so we also try a ACCESS_CODE.
1444 if (unlikely(get_physical_address(env, &ctx, addr, 0,
1445 ACCESS_CODE) != 0)) {
1446 return -1;
1450 return ctx.raddr & TARGET_PAGE_MASK;
1453 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1454 int rw)
1456 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1457 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1458 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1459 env->spr[SPR_BOOKE_MAS3] = 0;
1460 env->spr[SPR_BOOKE_MAS6] = 0;
1461 env->spr[SPR_BOOKE_MAS7] = 0;
1463 /* AS */
1464 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1465 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1466 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1469 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1470 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1472 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1473 case MAS4_TIDSELD_PID0:
1474 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1475 break;
1476 case MAS4_TIDSELD_PID1:
1477 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1478 break;
1479 case MAS4_TIDSELD_PID2:
1480 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1481 break;
1484 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1486 /* next victim logic */
1487 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1488 env->last_way++;
1489 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1490 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1493 /* Perform address translation */
1494 static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
1495 int rw, int mmu_idx)
1497 CPUState *cs = CPU(ppc_env_get_cpu(env));
1498 mmu_ctx_t ctx;
1499 int access_type;
1500 int ret = 0;
1502 if (rw == 2) {
1503 /* code access */
1504 rw = 0;
1505 access_type = ACCESS_CODE;
1506 } else {
1507 /* data access */
1508 access_type = env->access_type;
1510 ret = get_physical_address(env, &ctx, address, rw, access_type);
1511 if (ret == 0) {
1512 tlb_set_page(env, address & TARGET_PAGE_MASK,
1513 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1514 mmu_idx, TARGET_PAGE_SIZE);
1515 ret = 0;
1516 } else if (ret < 0) {
1517 LOG_MMU_STATE(cs);
1518 if (access_type == ACCESS_CODE) {
1519 switch (ret) {
1520 case -1:
1521 /* No matches in page tables or TLB */
1522 switch (env->mmu_model) {
1523 case POWERPC_MMU_SOFT_6xx:
1524 cs->exception_index = POWERPC_EXCP_IFTLB;
1525 env->error_code = 1 << 18;
1526 env->spr[SPR_IMISS] = address;
1527 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1528 goto tlb_miss;
1529 case POWERPC_MMU_SOFT_74xx:
1530 cs->exception_index = POWERPC_EXCP_IFTLB;
1531 goto tlb_miss_74xx;
1532 case POWERPC_MMU_SOFT_4xx:
1533 case POWERPC_MMU_SOFT_4xx_Z:
1534 cs->exception_index = POWERPC_EXCP_ITLB;
1535 env->error_code = 0;
1536 env->spr[SPR_40x_DEAR] = address;
1537 env->spr[SPR_40x_ESR] = 0x00000000;
1538 break;
1539 case POWERPC_MMU_BOOKE206:
1540 booke206_update_mas_tlb_miss(env, address, rw);
1541 /* fall through */
1542 case POWERPC_MMU_BOOKE:
1543 cs->exception_index = POWERPC_EXCP_ITLB;
1544 env->error_code = 0;
1545 env->spr[SPR_BOOKE_DEAR] = address;
1546 return -1;
1547 case POWERPC_MMU_MPC8xx:
1548 /* XXX: TODO */
1549 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1550 break;
1551 case POWERPC_MMU_REAL:
1552 cpu_abort(cs, "PowerPC in real mode should never raise "
1553 "any MMU exceptions\n");
1554 return -1;
1555 default:
1556 cpu_abort(cs, "Unknown or invalid MMU model\n");
1557 return -1;
1559 break;
1560 case -2:
1561 /* Access rights violation */
1562 cs->exception_index = POWERPC_EXCP_ISI;
1563 env->error_code = 0x08000000;
1564 break;
1565 case -3:
1566 /* No execute protection violation */
1567 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1568 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1569 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1571 cs->exception_index = POWERPC_EXCP_ISI;
1572 env->error_code = 0x10000000;
1573 break;
1574 case -4:
1575 /* Direct store exception */
1576 /* No code fetch is allowed in direct-store areas */
1577 cs->exception_index = POWERPC_EXCP_ISI;
1578 env->error_code = 0x10000000;
1579 break;
1581 } else {
1582 switch (ret) {
1583 case -1:
1584 /* No matches in page tables or TLB */
1585 switch (env->mmu_model) {
1586 case POWERPC_MMU_SOFT_6xx:
1587 if (rw == 1) {
1588 cs->exception_index = POWERPC_EXCP_DSTLB;
1589 env->error_code = 1 << 16;
1590 } else {
1591 cs->exception_index = POWERPC_EXCP_DLTLB;
1592 env->error_code = 0;
1594 env->spr[SPR_DMISS] = address;
1595 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1596 tlb_miss:
1597 env->error_code |= ctx.key << 19;
1598 env->spr[SPR_HASH1] = env->htab_base +
1599 get_pteg_offset32(env, ctx.hash[0]);
1600 env->spr[SPR_HASH2] = env->htab_base +
1601 get_pteg_offset32(env, ctx.hash[1]);
1602 break;
1603 case POWERPC_MMU_SOFT_74xx:
1604 if (rw == 1) {
1605 cs->exception_index = POWERPC_EXCP_DSTLB;
1606 } else {
1607 cs->exception_index = POWERPC_EXCP_DLTLB;
1609 tlb_miss_74xx:
1610 /* Implement LRU algorithm */
1611 env->error_code = ctx.key << 19;
1612 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1613 ((env->last_way + 1) & (env->nb_ways - 1));
1614 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1615 break;
1616 case POWERPC_MMU_SOFT_4xx:
1617 case POWERPC_MMU_SOFT_4xx_Z:
1618 cs->exception_index = POWERPC_EXCP_DTLB;
1619 env->error_code = 0;
1620 env->spr[SPR_40x_DEAR] = address;
1621 if (rw) {
1622 env->spr[SPR_40x_ESR] = 0x00800000;
1623 } else {
1624 env->spr[SPR_40x_ESR] = 0x00000000;
1626 break;
1627 case POWERPC_MMU_MPC8xx:
1628 /* XXX: TODO */
1629 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1630 break;
1631 case POWERPC_MMU_BOOKE206:
1632 booke206_update_mas_tlb_miss(env, address, rw);
1633 /* fall through */
1634 case POWERPC_MMU_BOOKE:
1635 cs->exception_index = POWERPC_EXCP_DTLB;
1636 env->error_code = 0;
1637 env->spr[SPR_BOOKE_DEAR] = address;
1638 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1639 return -1;
1640 case POWERPC_MMU_REAL:
1641 cpu_abort(cs, "PowerPC in real mode should never raise "
1642 "any MMU exceptions\n");
1643 return -1;
1644 default:
1645 cpu_abort(cs, "Unknown or invalid MMU model\n");
1646 return -1;
1648 break;
1649 case -2:
1650 /* Access rights violation */
1651 cs->exception_index = POWERPC_EXCP_DSI;
1652 env->error_code = 0;
1653 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1654 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1655 env->spr[SPR_40x_DEAR] = address;
1656 if (rw) {
1657 env->spr[SPR_40x_ESR] |= 0x00800000;
1659 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1660 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1661 env->spr[SPR_BOOKE_DEAR] = address;
1662 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1663 } else {
1664 env->spr[SPR_DAR] = address;
1665 if (rw == 1) {
1666 env->spr[SPR_DSISR] = 0x0A000000;
1667 } else {
1668 env->spr[SPR_DSISR] = 0x08000000;
1671 break;
1672 case -4:
1673 /* Direct store exception */
1674 switch (access_type) {
1675 case ACCESS_FLOAT:
1676 /* Floating point load/store */
1677 cs->exception_index = POWERPC_EXCP_ALIGN;
1678 env->error_code = POWERPC_EXCP_ALIGN_FP;
1679 env->spr[SPR_DAR] = address;
1680 break;
1681 case ACCESS_RES:
1682 /* lwarx, ldarx or stwcx. */
1683 cs->exception_index = POWERPC_EXCP_DSI;
1684 env->error_code = 0;
1685 env->spr[SPR_DAR] = address;
1686 if (rw == 1) {
1687 env->spr[SPR_DSISR] = 0x06000000;
1688 } else {
1689 env->spr[SPR_DSISR] = 0x04000000;
1691 break;
1692 case ACCESS_EXT:
1693 /* eciwx or ecowx */
1694 cs->exception_index = POWERPC_EXCP_DSI;
1695 env->error_code = 0;
1696 env->spr[SPR_DAR] = address;
1697 if (rw == 1) {
1698 env->spr[SPR_DSISR] = 0x06100000;
1699 } else {
1700 env->spr[SPR_DSISR] = 0x04100000;
1702 break;
1703 default:
1704 printf("DSI: invalid exception (%d)\n", ret);
1705 cs->exception_index = POWERPC_EXCP_PROGRAM;
1706 env->error_code =
1707 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1708 env->spr[SPR_DAR] = address;
1709 break;
1711 break;
1714 #if 0
1715 printf("%s: set exception to %d %02x\n", __func__,
1716 cs->exception, env->error_code);
1717 #endif
1718 ret = 1;
1721 return ret;
1724 /*****************************************************************************/
1725 /* BATs management */
1726 #if !defined(FLUSH_ALL_TLBS)
1727 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1728 target_ulong mask)
1730 target_ulong base, end, page;
1732 base = BATu & ~0x0001FFFF;
1733 end = base + mask + 0x00020000;
1734 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1735 TARGET_FMT_lx ")\n", base, end, mask);
1736 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
1737 tlb_flush_page(env, page);
1739 LOG_BATS("Flush done\n");
1741 #endif
1743 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1744 target_ulong value)
1746 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1747 nr, ul == 0 ? 'u' : 'l', value, env->nip);
1750 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1752 target_ulong mask;
1754 dump_store_bat(env, 'I', 0, nr, value);
1755 if (env->IBAT[0][nr] != value) {
1756 mask = (value << 15) & 0x0FFE0000UL;
1757 #if !defined(FLUSH_ALL_TLBS)
1758 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1759 #endif
1760 /* When storing valid upper BAT, mask BEPI and BRPN
1761 * and invalidate all TLBs covered by this BAT
1763 mask = (value << 15) & 0x0FFE0000UL;
1764 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1765 (value & ~0x0001FFFFUL & ~mask);
1766 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1767 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1768 #if !defined(FLUSH_ALL_TLBS)
1769 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1770 #else
1771 tlb_flush(env, 1);
1772 #endif
1776 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1778 dump_store_bat(env, 'I', 1, nr, value);
1779 env->IBAT[1][nr] = value;
1782 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1784 target_ulong mask;
1786 dump_store_bat(env, 'D', 0, nr, value);
1787 if (env->DBAT[0][nr] != value) {
1788 /* When storing valid upper BAT, mask BEPI and BRPN
1789 * and invalidate all TLBs covered by this BAT
1791 mask = (value << 15) & 0x0FFE0000UL;
1792 #if !defined(FLUSH_ALL_TLBS)
1793 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1794 #endif
1795 mask = (value << 15) & 0x0FFE0000UL;
1796 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1797 (value & ~0x0001FFFFUL & ~mask);
1798 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1799 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1800 #if !defined(FLUSH_ALL_TLBS)
1801 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1802 #else
1803 tlb_flush(env, 1);
1804 #endif
1808 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1810 dump_store_bat(env, 'D', 1, nr, value);
1811 env->DBAT[1][nr] = value;
1814 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
1816 target_ulong mask;
1817 #if defined(FLUSH_ALL_TLBS)
1818 int do_inval;
1819 #endif
1821 dump_store_bat(env, 'I', 0, nr, value);
1822 if (env->IBAT[0][nr] != value) {
1823 #if defined(FLUSH_ALL_TLBS)
1824 do_inval = 0;
1825 #endif
1826 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1827 if (env->IBAT[1][nr] & 0x40) {
1828 /* Invalidate BAT only if it is valid */
1829 #if !defined(FLUSH_ALL_TLBS)
1830 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1831 #else
1832 do_inval = 1;
1833 #endif
1835 /* When storing valid upper BAT, mask BEPI and BRPN
1836 * and invalidate all TLBs covered by this BAT
1838 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1839 (value & ~0x0001FFFFUL & ~mask);
1840 env->DBAT[0][nr] = env->IBAT[0][nr];
1841 if (env->IBAT[1][nr] & 0x40) {
1842 #if !defined(FLUSH_ALL_TLBS)
1843 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1844 #else
1845 do_inval = 1;
1846 #endif
1848 #if defined(FLUSH_ALL_TLBS)
1849 if (do_inval) {
1850 tlb_flush(env, 1);
1852 #endif
1856 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
1858 #if !defined(FLUSH_ALL_TLBS)
1859 target_ulong mask;
1860 #else
1861 int do_inval;
1862 #endif
1864 dump_store_bat(env, 'I', 1, nr, value);
1865 if (env->IBAT[1][nr] != value) {
1866 #if defined(FLUSH_ALL_TLBS)
1867 do_inval = 0;
1868 #endif
1869 if (env->IBAT[1][nr] & 0x40) {
1870 #if !defined(FLUSH_ALL_TLBS)
1871 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1872 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1873 #else
1874 do_inval = 1;
1875 #endif
1877 if (value & 0x40) {
1878 #if !defined(FLUSH_ALL_TLBS)
1879 mask = (value << 17) & 0x0FFE0000UL;
1880 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1881 #else
1882 do_inval = 1;
1883 #endif
1885 env->IBAT[1][nr] = value;
1886 env->DBAT[1][nr] = value;
1887 #if defined(FLUSH_ALL_TLBS)
1888 if (do_inval) {
1889 tlb_flush(env, 1);
1891 #endif
1895 /*****************************************************************************/
1896 /* TLB management */
1897 void ppc_tlb_invalidate_all(CPUPPCState *env)
1899 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1901 switch (env->mmu_model) {
1902 case POWERPC_MMU_SOFT_6xx:
1903 case POWERPC_MMU_SOFT_74xx:
1904 ppc6xx_tlb_invalidate_all(env);
1905 break;
1906 case POWERPC_MMU_SOFT_4xx:
1907 case POWERPC_MMU_SOFT_4xx_Z:
1908 ppc4xx_tlb_invalidate_all(env);
1909 break;
1910 case POWERPC_MMU_REAL:
1911 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1912 break;
1913 case POWERPC_MMU_MPC8xx:
1914 /* XXX: TODO */
1915 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1916 break;
1917 case POWERPC_MMU_BOOKE:
1918 tlb_flush(env, 1);
1919 break;
1920 case POWERPC_MMU_BOOKE206:
1921 booke206_flush_tlb(env, -1, 0);
1922 break;
1923 case POWERPC_MMU_32B:
1924 case POWERPC_MMU_601:
1925 #if defined(TARGET_PPC64)
1926 case POWERPC_MMU_64B:
1927 case POWERPC_MMU_2_06:
1928 case POWERPC_MMU_2_06a:
1929 case POWERPC_MMU_2_06d:
1930 #endif /* defined(TARGET_PPC64) */
1931 tlb_flush(env, 1);
1932 break;
1933 default:
1934 /* XXX: TODO */
1935 cpu_abort(CPU(cpu), "Unknown MMU model\n");
1936 break;
1940 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
1942 #if !defined(FLUSH_ALL_TLBS)
1943 PowerPCCPU *cpu = ppc_env_get_cpu(env);
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_SOFT_4xx:
1955 case POWERPC_MMU_SOFT_4xx_Z:
1956 ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
1957 break;
1958 case POWERPC_MMU_REAL:
1959 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1960 break;
1961 case POWERPC_MMU_MPC8xx:
1962 /* XXX: TODO */
1963 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1964 break;
1965 case POWERPC_MMU_BOOKE:
1966 /* XXX: TODO */
1967 cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
1968 break;
1969 case POWERPC_MMU_BOOKE206:
1970 /* XXX: TODO */
1971 cpu_abort(CPU(cpu), "BookE 2.06 MMU model is not implemented\n");
1972 break;
1973 case POWERPC_MMU_32B:
1974 case POWERPC_MMU_601:
1975 /* tlbie invalidate TLBs for all segments */
1976 addr &= ~((target_ulong)-1ULL << 28);
1977 /* XXX: this case should be optimized,
1978 * giving a mask to tlb_flush_page
1980 tlb_flush_page(env, addr | (0x0 << 28));
1981 tlb_flush_page(env, addr | (0x1 << 28));
1982 tlb_flush_page(env, addr | (0x2 << 28));
1983 tlb_flush_page(env, addr | (0x3 << 28));
1984 tlb_flush_page(env, addr | (0x4 << 28));
1985 tlb_flush_page(env, addr | (0x5 << 28));
1986 tlb_flush_page(env, addr | (0x6 << 28));
1987 tlb_flush_page(env, addr | (0x7 << 28));
1988 tlb_flush_page(env, addr | (0x8 << 28));
1989 tlb_flush_page(env, addr | (0x9 << 28));
1990 tlb_flush_page(env, addr | (0xA << 28));
1991 tlb_flush_page(env, addr | (0xB << 28));
1992 tlb_flush_page(env, addr | (0xC << 28));
1993 tlb_flush_page(env, addr | (0xD << 28));
1994 tlb_flush_page(env, addr | (0xE << 28));
1995 tlb_flush_page(env, addr | (0xF << 28));
1996 break;
1997 #if defined(TARGET_PPC64)
1998 case POWERPC_MMU_64B:
1999 case POWERPC_MMU_2_06:
2000 case POWERPC_MMU_2_06a:
2001 case POWERPC_MMU_2_06d:
2002 /* tlbie invalidate TLBs for all segments */
2003 /* XXX: given the fact that there are too many segments to invalidate,
2004 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
2005 * we just invalidate all TLBs
2007 tlb_flush(env, 1);
2008 break;
2009 #endif /* defined(TARGET_PPC64) */
2010 default:
2011 /* XXX: TODO */
2012 cpu_abort(CPU(cpu), "Unknown MMU model\n");
2013 break;
2015 #else
2016 ppc_tlb_invalidate_all(env);
2017 #endif
2020 /*****************************************************************************/
2021 /* Special registers manipulation */
2022 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2024 LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
2025 assert(!env->external_htab);
2026 if (env->spr[SPR_SDR1] != value) {
2027 env->spr[SPR_SDR1] = value;
2028 #if defined(TARGET_PPC64)
2029 if (env->mmu_model & POWERPC_MMU_64) {
2030 target_ulong htabsize = value & SDR_64_HTABSIZE;
2032 if (htabsize > 28) {
2033 fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
2034 " stored in SDR1\n", htabsize);
2035 htabsize = 28;
2037 env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
2038 env->htab_base = value & SDR_64_HTABORG;
2039 } else
2040 #endif /* defined(TARGET_PPC64) */
2042 /* FIXME: Should check for valid HTABMASK values */
2043 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2044 env->htab_base = value & SDR_32_HTABORG;
2046 tlb_flush(env, 1);
2050 /* Segment registers load and store */
2051 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2053 #if defined(TARGET_PPC64)
2054 if (env->mmu_model & POWERPC_MMU_64) {
2055 /* XXX */
2056 return 0;
2058 #endif
2059 return env->sr[sr_num];
2062 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2064 LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2065 (int)srnum, value, env->sr[srnum]);
2066 #if defined(TARGET_PPC64)
2067 if (env->mmu_model & POWERPC_MMU_64) {
2068 uint64_t rb = 0, rs = 0;
2070 /* ESID = srnum */
2071 rb |= ((uint32_t)srnum & 0xf) << 28;
2072 /* Set the valid bit */
2073 rb |= SLB_ESID_V;
2074 /* Index = ESID */
2075 rb |= (uint32_t)srnum;
2077 /* VSID = VSID */
2078 rs |= (value & 0xfffffff) << 12;
2079 /* flags = flags */
2080 rs |= ((value >> 27) & 0xf) << 8;
2082 ppc_store_slb(env, rb, rs);
2083 } else
2084 #endif
2085 if (env->sr[srnum] != value) {
2086 env->sr[srnum] = value;
2087 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2088 flusing the whole TLB. */
2089 #if !defined(FLUSH_ALL_TLBS) && 0
2091 target_ulong page, end;
2092 /* Invalidate 256 MB of virtual memory */
2093 page = (16 << 20) * srnum;
2094 end = page + (16 << 20);
2095 for (; page != end; page += TARGET_PAGE_SIZE) {
2096 tlb_flush_page(env, page);
2099 #else
2100 tlb_flush(env, 1);
2101 #endif
2105 /* TLB management */
2106 void helper_tlbia(CPUPPCState *env)
2108 ppc_tlb_invalidate_all(env);
2111 void helper_tlbie(CPUPPCState *env, target_ulong addr)
2113 ppc_tlb_invalidate_one(env, addr);
2116 /* Software driven TLBs management */
2117 /* PowerPC 602/603 software TLB load instructions helpers */
2118 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2120 target_ulong RPN, CMP, EPN;
2121 int way;
2123 RPN = env->spr[SPR_RPA];
2124 if (is_code) {
2125 CMP = env->spr[SPR_ICMP];
2126 EPN = env->spr[SPR_IMISS];
2127 } else {
2128 CMP = env->spr[SPR_DCMP];
2129 EPN = env->spr[SPR_DMISS];
2131 way = (env->spr[SPR_SRR1] >> 17) & 1;
2132 (void)EPN; /* avoid a compiler warning */
2133 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2134 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2135 RPN, way);
2136 /* Store this TLB */
2137 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2138 way, is_code, CMP, RPN);
2141 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2143 do_6xx_tlb(env, EPN, 0);
2146 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2148 do_6xx_tlb(env, EPN, 1);
2151 /* PowerPC 74xx software TLB load instructions helpers */
2152 static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2154 target_ulong RPN, CMP, EPN;
2155 int way;
2157 RPN = env->spr[SPR_PTELO];
2158 CMP = env->spr[SPR_PTEHI];
2159 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2160 way = env->spr[SPR_TLBMISS] & 0x3;
2161 (void)EPN; /* avoid a compiler warning */
2162 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2163 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2164 RPN, way);
2165 /* Store this TLB */
2166 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2167 way, is_code, CMP, RPN);
2170 void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2172 do_74xx_tlb(env, EPN, 0);
2175 void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2177 do_74xx_tlb(env, EPN, 1);
2180 /*****************************************************************************/
2181 /* PowerPC 601 specific instructions (POWER bridge) */
2183 target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2185 mmu_ctx_t ctx;
2186 int nb_BATs;
2187 target_ulong ret = 0;
2189 /* We don't have to generate many instances of this instruction,
2190 * as rac is supervisor only.
2192 /* XXX: FIX THIS: Pretend we have no BAT */
2193 nb_BATs = env->nb_BATs;
2194 env->nb_BATs = 0;
2195 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2196 ret = ctx.raddr;
2198 env->nb_BATs = nb_BATs;
2199 return ret;
2202 static inline target_ulong booke_tlb_to_page_size(int size)
2204 return 1024 << (2 * size);
2207 static inline int booke_page_size_to_tlb(target_ulong page_size)
2209 int size;
2211 switch (page_size) {
2212 case 0x00000400UL:
2213 size = 0x0;
2214 break;
2215 case 0x00001000UL:
2216 size = 0x1;
2217 break;
2218 case 0x00004000UL:
2219 size = 0x2;
2220 break;
2221 case 0x00010000UL:
2222 size = 0x3;
2223 break;
2224 case 0x00040000UL:
2225 size = 0x4;
2226 break;
2227 case 0x00100000UL:
2228 size = 0x5;
2229 break;
2230 case 0x00400000UL:
2231 size = 0x6;
2232 break;
2233 case 0x01000000UL:
2234 size = 0x7;
2235 break;
2236 case 0x04000000UL:
2237 size = 0x8;
2238 break;
2239 case 0x10000000UL:
2240 size = 0x9;
2241 break;
2242 case 0x40000000UL:
2243 size = 0xA;
2244 break;
2245 #if defined(TARGET_PPC64)
2246 case 0x000100000000ULL:
2247 size = 0xB;
2248 break;
2249 case 0x000400000000ULL:
2250 size = 0xC;
2251 break;
2252 case 0x001000000000ULL:
2253 size = 0xD;
2254 break;
2255 case 0x004000000000ULL:
2256 size = 0xE;
2257 break;
2258 case 0x010000000000ULL:
2259 size = 0xF;
2260 break;
2261 #endif
2262 default:
2263 size = -1;
2264 break;
2267 return size;
2270 /* Helpers for 4xx TLB management */
2271 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2273 #define PPC4XX_TLBHI_V 0x00000040
2274 #define PPC4XX_TLBHI_E 0x00000020
2275 #define PPC4XX_TLBHI_SIZE_MIN 0
2276 #define PPC4XX_TLBHI_SIZE_MAX 7
2277 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2278 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2279 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2281 #define PPC4XX_TLBLO_EX 0x00000200
2282 #define PPC4XX_TLBLO_WR 0x00000100
2283 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2284 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2286 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2288 ppcemb_tlb_t *tlb;
2289 target_ulong ret;
2290 int size;
2292 entry &= PPC4XX_TLB_ENTRY_MASK;
2293 tlb = &env->tlb.tlbe[entry];
2294 ret = tlb->EPN;
2295 if (tlb->prot & PAGE_VALID) {
2296 ret |= PPC4XX_TLBHI_V;
2298 size = booke_page_size_to_tlb(tlb->size);
2299 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2300 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2302 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2303 env->spr[SPR_40x_PID] = tlb->PID;
2304 return ret;
2307 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2309 ppcemb_tlb_t *tlb;
2310 target_ulong ret;
2312 entry &= PPC4XX_TLB_ENTRY_MASK;
2313 tlb = &env->tlb.tlbe[entry];
2314 ret = tlb->RPN;
2315 if (tlb->prot & PAGE_EXEC) {
2316 ret |= PPC4XX_TLBLO_EX;
2318 if (tlb->prot & PAGE_WRITE) {
2319 ret |= PPC4XX_TLBLO_WR;
2321 return ret;
2324 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2325 target_ulong val)
2327 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2328 ppcemb_tlb_t *tlb;
2329 target_ulong page, end;
2331 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2332 val);
2333 entry &= PPC4XX_TLB_ENTRY_MASK;
2334 tlb = &env->tlb.tlbe[entry];
2335 /* Invalidate previous TLB (if it's valid) */
2336 if (tlb->prot & PAGE_VALID) {
2337 end = tlb->EPN + tlb->size;
2338 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2339 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2340 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2341 tlb_flush_page(env, page);
2344 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2345 & PPC4XX_TLBHI_SIZE_MASK);
2346 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2347 * If this ever occurs, one should use the ppcemb target instead
2348 * of the ppc or ppc64 one
2350 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2351 cpu_abort(CPU(cpu), "TLB size " TARGET_FMT_lu " < %u "
2352 "are not supported (%d)\n",
2353 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2355 tlb->EPN = val & ~(tlb->size - 1);
2356 if (val & PPC4XX_TLBHI_V) {
2357 tlb->prot |= PAGE_VALID;
2358 if (val & PPC4XX_TLBHI_E) {
2359 /* XXX: TO BE FIXED */
2360 cpu_abort(CPU(cpu),
2361 "Little-endian TLB entries are not supported by now\n");
2363 } else {
2364 tlb->prot &= ~PAGE_VALID;
2366 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2367 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2368 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2369 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2370 tlb->prot & PAGE_READ ? 'r' : '-',
2371 tlb->prot & PAGE_WRITE ? 'w' : '-',
2372 tlb->prot & PAGE_EXEC ? 'x' : '-',
2373 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2374 /* Invalidate new TLB (if valid) */
2375 if (tlb->prot & PAGE_VALID) {
2376 end = tlb->EPN + tlb->size;
2377 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2378 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2379 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2380 tlb_flush_page(env, page);
2385 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2386 target_ulong val)
2388 ppcemb_tlb_t *tlb;
2390 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2391 val);
2392 entry &= PPC4XX_TLB_ENTRY_MASK;
2393 tlb = &env->tlb.tlbe[entry];
2394 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2395 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2396 tlb->prot = PAGE_READ;
2397 if (val & PPC4XX_TLBLO_EX) {
2398 tlb->prot |= PAGE_EXEC;
2400 if (val & PPC4XX_TLBLO_WR) {
2401 tlb->prot |= PAGE_WRITE;
2403 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2404 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2405 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2406 tlb->prot & PAGE_READ ? 'r' : '-',
2407 tlb->prot & PAGE_WRITE ? 'w' : '-',
2408 tlb->prot & PAGE_EXEC ? 'x' : '-',
2409 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2412 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2414 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2417 /* PowerPC 440 TLB management */
2418 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2419 target_ulong value)
2421 ppcemb_tlb_t *tlb;
2422 target_ulong EPN, RPN, size;
2423 int do_flush_tlbs;
2425 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2426 __func__, word, (int)entry, value);
2427 do_flush_tlbs = 0;
2428 entry &= 0x3F;
2429 tlb = &env->tlb.tlbe[entry];
2430 switch (word) {
2431 default:
2432 /* Just here to please gcc */
2433 case 0:
2434 EPN = value & 0xFFFFFC00;
2435 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2436 do_flush_tlbs = 1;
2438 tlb->EPN = EPN;
2439 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2440 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2441 do_flush_tlbs = 1;
2443 tlb->size = size;
2444 tlb->attr &= ~0x1;
2445 tlb->attr |= (value >> 8) & 1;
2446 if (value & 0x200) {
2447 tlb->prot |= PAGE_VALID;
2448 } else {
2449 if (tlb->prot & PAGE_VALID) {
2450 tlb->prot &= ~PAGE_VALID;
2451 do_flush_tlbs = 1;
2454 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2455 if (do_flush_tlbs) {
2456 tlb_flush(env, 1);
2458 break;
2459 case 1:
2460 RPN = value & 0xFFFFFC0F;
2461 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2462 tlb_flush(env, 1);
2464 tlb->RPN = RPN;
2465 break;
2466 case 2:
2467 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2468 tlb->prot = tlb->prot & PAGE_VALID;
2469 if (value & 0x1) {
2470 tlb->prot |= PAGE_READ << 4;
2472 if (value & 0x2) {
2473 tlb->prot |= PAGE_WRITE << 4;
2475 if (value & 0x4) {
2476 tlb->prot |= PAGE_EXEC << 4;
2478 if (value & 0x8) {
2479 tlb->prot |= PAGE_READ;
2481 if (value & 0x10) {
2482 tlb->prot |= PAGE_WRITE;
2484 if (value & 0x20) {
2485 tlb->prot |= PAGE_EXEC;
2487 break;
2491 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2492 target_ulong entry)
2494 ppcemb_tlb_t *tlb;
2495 target_ulong ret;
2496 int size;
2498 entry &= 0x3F;
2499 tlb = &env->tlb.tlbe[entry];
2500 switch (word) {
2501 default:
2502 /* Just here to please gcc */
2503 case 0:
2504 ret = tlb->EPN;
2505 size = booke_page_size_to_tlb(tlb->size);
2506 if (size < 0 || size > 0xF) {
2507 size = 1;
2509 ret |= size << 4;
2510 if (tlb->attr & 0x1) {
2511 ret |= 0x100;
2513 if (tlb->prot & PAGE_VALID) {
2514 ret |= 0x200;
2516 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2517 env->spr[SPR_440_MMUCR] |= tlb->PID;
2518 break;
2519 case 1:
2520 ret = tlb->RPN;
2521 break;
2522 case 2:
2523 ret = tlb->attr & ~0x1;
2524 if (tlb->prot & (PAGE_READ << 4)) {
2525 ret |= 0x1;
2527 if (tlb->prot & (PAGE_WRITE << 4)) {
2528 ret |= 0x2;
2530 if (tlb->prot & (PAGE_EXEC << 4)) {
2531 ret |= 0x4;
2533 if (tlb->prot & PAGE_READ) {
2534 ret |= 0x8;
2536 if (tlb->prot & PAGE_WRITE) {
2537 ret |= 0x10;
2539 if (tlb->prot & PAGE_EXEC) {
2540 ret |= 0x20;
2542 break;
2544 return ret;
2547 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2549 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2552 /* PowerPC BookE 2.06 TLB management */
2554 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2556 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2557 uint32_t tlbncfg = 0;
2558 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2559 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2560 int tlb;
2562 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2563 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2565 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2566 cpu_abort(CPU(cpu), "we don't support HES yet\n");
2569 return booke206_get_tlbm(env, tlb, ea, esel);
2572 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2574 env->spr[pidn] = pid;
2575 /* changing PIDs mean we're in a different address space now */
2576 tlb_flush(env, 1);
2579 void helper_booke206_tlbwe(CPUPPCState *env)
2581 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2582 uint32_t tlbncfg, tlbn;
2583 ppcmas_tlb_t *tlb;
2584 uint32_t size_tlb, size_ps;
2585 target_ulong mask;
2588 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2589 case MAS0_WQ_ALWAYS:
2590 /* good to go, write that entry */
2591 break;
2592 case MAS0_WQ_COND:
2593 /* XXX check if reserved */
2594 if (0) {
2595 return;
2597 break;
2598 case MAS0_WQ_CLR_RSRV:
2599 /* XXX clear entry */
2600 return;
2601 default:
2602 /* no idea what to do */
2603 return;
2606 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2607 !msr_gs) {
2608 /* XXX we don't support direct LRAT setting yet */
2609 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2610 return;
2613 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2614 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2616 tlb = booke206_cur_tlb(env);
2618 if (!tlb) {
2619 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2620 POWERPC_EXCP_INVAL |
2621 POWERPC_EXCP_INVAL_INVAL);
2624 /* check that we support the targeted size */
2625 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2626 size_ps = booke206_tlbnps(env, tlbn);
2627 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2628 !(size_ps & (1 << size_tlb))) {
2629 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2630 POWERPC_EXCP_INVAL |
2631 POWERPC_EXCP_INVAL_INVAL);
2634 if (msr_gs) {
2635 cpu_abort(CPU(cpu), "missing HV implementation\n");
2637 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2638 env->spr[SPR_BOOKE_MAS3];
2639 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2641 /* MAV 1.0 only */
2642 if (!(tlbncfg & TLBnCFG_AVAIL)) {
2643 /* force !AVAIL TLB entries to correct page size */
2644 tlb->mas1 &= ~MAS1_TSIZE_MASK;
2645 /* XXX can be configured in MMUCSR0 */
2646 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2649 /* Make a mask from TLB size to discard invalid bits in EPN field */
2650 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2651 /* Add a mask for page attributes */
2652 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2654 if (!msr_cm) {
2655 /* Executing a tlbwe instruction in 32-bit mode will set
2656 * bits 0:31 of the TLB EPN field to zero.
2658 mask &= 0xffffffff;
2661 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
2663 if (!(tlbncfg & TLBnCFG_IPROT)) {
2664 /* no IPROT supported by TLB */
2665 tlb->mas1 &= ~MAS1_IPROT;
2668 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
2669 tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
2670 } else {
2671 tlb_flush(env, 1);
2675 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2677 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2678 int way = booke206_tlbm_to_way(env, tlb);
2680 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2681 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2682 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2684 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2685 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2686 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2687 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2690 void helper_booke206_tlbre(CPUPPCState *env)
2692 ppcmas_tlb_t *tlb = NULL;
2694 tlb = booke206_cur_tlb(env);
2695 if (!tlb) {
2696 env->spr[SPR_BOOKE_MAS1] = 0;
2697 } else {
2698 booke206_tlb_to_mas(env, tlb);
2702 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
2704 ppcmas_tlb_t *tlb = NULL;
2705 int i, j;
2706 hwaddr raddr;
2707 uint32_t spid, sas;
2709 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2710 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2712 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2713 int ways = booke206_tlb_ways(env, i);
2715 for (j = 0; j < ways; j++) {
2716 tlb = booke206_get_tlbm(env, i, address, j);
2718 if (!tlb) {
2719 continue;
2722 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2723 continue;
2726 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2727 continue;
2730 booke206_tlb_to_mas(env, tlb);
2731 return;
2735 /* no entry found, fill with defaults */
2736 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2737 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2738 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2739 env->spr[SPR_BOOKE_MAS3] = 0;
2740 env->spr[SPR_BOOKE_MAS7] = 0;
2742 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2743 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2746 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2747 << MAS1_TID_SHIFT;
2749 /* next victim logic */
2750 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2751 env->last_way++;
2752 env->last_way &= booke206_tlb_ways(env, 0) - 1;
2753 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2756 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2757 uint32_t ea)
2759 int i;
2760 int ways = booke206_tlb_ways(env, tlbn);
2761 target_ulong mask;
2763 for (i = 0; i < ways; i++) {
2764 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2765 if (!tlb) {
2766 continue;
2768 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2769 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2770 !(tlb->mas1 & MAS1_IPROT)) {
2771 tlb->mas1 &= ~MAS1_VALID;
2776 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
2778 if (address & 0x4) {
2779 /* flush all entries */
2780 if (address & 0x8) {
2781 /* flush all of TLB1 */
2782 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2783 } else {
2784 /* flush all of TLB0 */
2785 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2787 return;
2790 if (address & 0x8) {
2791 /* flush TLB1 entries */
2792 booke206_invalidate_ea_tlb(env, 1, address);
2793 tlb_flush(env, 1);
2794 } else {
2795 /* flush TLB0 entries */
2796 booke206_invalidate_ea_tlb(env, 0, address);
2797 tlb_flush_page(env, address & MAS2_EPN_MASK);
2801 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
2803 /* XXX missing LPID handling */
2804 booke206_flush_tlb(env, -1, 1);
2807 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
2809 int i, j;
2810 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2811 ppcmas_tlb_t *tlb = env->tlb.tlbm;
2812 int tlb_size;
2814 /* XXX missing LPID handling */
2815 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2816 tlb_size = booke206_tlb_size(env, i);
2817 for (j = 0; j < tlb_size; j++) {
2818 if (!(tlb[j].mas1 & MAS1_IPROT) &&
2819 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2820 tlb[j].mas1 &= ~MAS1_VALID;
2823 tlb += booke206_tlb_size(env, i);
2825 tlb_flush(env, 1);
2828 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
2830 int i, j;
2831 ppcmas_tlb_t *tlb;
2832 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2833 int pid = tid >> MAS6_SPID_SHIFT;
2834 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2835 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
2836 /* XXX check for unsupported isize and raise an invalid opcode then */
2837 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
2838 /* XXX implement MAV2 handling */
2839 bool mav2 = false;
2841 /* XXX missing LPID handling */
2842 /* flush by pid and ea */
2843 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2844 int ways = booke206_tlb_ways(env, i);
2846 for (j = 0; j < ways; j++) {
2847 tlb = booke206_get_tlbm(env, i, address, j);
2848 if (!tlb) {
2849 continue;
2851 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
2852 (tlb->mas1 & MAS1_IPROT) ||
2853 ((tlb->mas1 & MAS1_IND) != ind) ||
2854 ((tlb->mas8 & MAS8_TGS) != sgs)) {
2855 continue;
2857 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
2858 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2859 continue;
2861 /* XXX e500mc doesn't match SAS, but other cores might */
2862 tlb->mas1 &= ~MAS1_VALID;
2865 tlb_flush(env, 1);
2868 void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
2870 int flags = 0;
2872 if (type & 2) {
2873 flags |= BOOKE206_FLUSH_TLB1;
2876 if (type & 4) {
2877 flags |= BOOKE206_FLUSH_TLB0;
2880 booke206_flush_tlb(env, flags, 1);
2884 /*****************************************************************************/
2886 #include "exec/softmmu_exec.h"
2888 #define MMUSUFFIX _mmu
2890 #define SHIFT 0
2891 #include "exec/softmmu_template.h"
2893 #define SHIFT 1
2894 #include "exec/softmmu_template.h"
2896 #define SHIFT 2
2897 #include "exec/softmmu_template.h"
2899 #define SHIFT 3
2900 #include "exec/softmmu_template.h"
2902 /* try to fill the TLB and return an exception if error. If retaddr is
2903 NULL, it means that the function was called in C code (i.e. not
2904 from generated code or from helper.c) */
2905 /* XXX: fix it to restore all registers */
2906 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
2907 uintptr_t retaddr)
2909 PowerPCCPU *cpu = POWERPC_CPU(cs);
2910 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
2911 CPUPPCState *env = &cpu->env;
2912 int ret;
2914 if (pcc->handle_mmu_fault) {
2915 ret = pcc->handle_mmu_fault(cpu, addr, is_write, mmu_idx);
2916 } else {
2917 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
2919 if (unlikely(ret != 0)) {
2920 if (likely(retaddr)) {
2921 /* now we have a real cpu fault */
2922 cpu_restore_state(cs, retaddr);
2924 helper_raise_exception_err(env, cs->exception_index, env->error_code);