qapi: Drop dead parameter in gen_params()
[qemu/ar7.git] / target-ppc / mmu_helper.c
blobe5ec8d61692d0da20e0e68b0165eefd6f4463188
1 /*
2 * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
4 * Copyright (c) 2003-2007 Jocelyn Mayer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #include "qemu/osdep.h"
20 #include "cpu.h"
21 #include "exec/helper-proto.h"
22 #include "sysemu/kvm.h"
23 #include "kvm_ppc.h"
24 #include "mmu-hash64.h"
25 #include "mmu-hash32.h"
26 #include "exec/cpu_ldst.h"
27 #include "exec/log.h"
29 //#define DEBUG_MMU
30 //#define DEBUG_BATS
31 //#define DEBUG_SOFTWARE_TLB
32 //#define DUMP_PAGE_TABLES
33 //#define FLUSH_ALL_TLBS
35 #ifdef DEBUG_MMU
36 # define LOG_MMU_STATE(cpu) log_cpu_state_mask(CPU_LOG_MMU, (cpu), 0)
37 #else
38 # define LOG_MMU_STATE(cpu) do { } while (0)
39 #endif
41 #ifdef DEBUG_SOFTWARE_TLB
42 # define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
43 #else
44 # define LOG_SWTLB(...) do { } while (0)
45 #endif
47 #ifdef DEBUG_BATS
48 # define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __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_mask(CPU_LOG_MMU, "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 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
179 } else {
180 /* Access right violation */
181 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
186 return ret;
189 static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
190 int ret, int rw)
192 int store = 0;
194 /* Update page flags */
195 if (!(*pte1p & 0x00000100)) {
196 /* Update accessed flag */
197 *pte1p |= 0x00000100;
198 store = 1;
200 if (!(*pte1p & 0x00000080)) {
201 if (rw == 1 && ret == 0) {
202 /* Update changed flag */
203 *pte1p |= 0x00000080;
204 store = 1;
205 } else {
206 /* Force page fault for first write access */
207 ctx->prot &= ~PAGE_WRITE;
211 return store;
214 /* Software driven TLB helpers */
215 static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
216 int way, int is_code)
218 int nr;
220 /* Select TLB num in a way from address */
221 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
222 /* Select TLB way */
223 nr += env->tlb_per_way * way;
224 /* 6xx have separate TLBs for instructions and data */
225 if (is_code && env->id_tlbs == 1) {
226 nr += env->nb_tlb;
229 return nr;
232 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
234 PowerPCCPU *cpu = ppc_env_get_cpu(env);
235 ppc6xx_tlb_t *tlb;
236 int nr, max;
238 /* LOG_SWTLB("Invalidate all TLBs\n"); */
239 /* Invalidate all defined software TLB */
240 max = env->nb_tlb;
241 if (env->id_tlbs == 1) {
242 max *= 2;
244 for (nr = 0; nr < max; nr++) {
245 tlb = &env->tlb.tlb6[nr];
246 pte_invalidate(&tlb->pte0);
248 tlb_flush(CPU(cpu), 1);
251 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
252 target_ulong eaddr,
253 int is_code, int match_epn)
255 #if !defined(FLUSH_ALL_TLBS)
256 CPUState *cs = CPU(ppc_env_get_cpu(env));
257 ppc6xx_tlb_t *tlb;
258 int way, nr;
260 /* Invalidate ITLB + DTLB, all ways */
261 for (way = 0; way < env->nb_ways; way++) {
262 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
263 tlb = &env->tlb.tlb6[nr];
264 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
265 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
266 env->nb_tlb, eaddr);
267 pte_invalidate(&tlb->pte0);
268 tlb_flush_page(cs, tlb->EPN);
271 #else
272 /* XXX: PowerPC specification say this is valid as well */
273 ppc6xx_tlb_invalidate_all(env);
274 #endif
277 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
278 target_ulong eaddr, int is_code)
280 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
283 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
284 int is_code, target_ulong pte0, target_ulong pte1)
286 ppc6xx_tlb_t *tlb;
287 int nr;
289 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
290 tlb = &env->tlb.tlb6[nr];
291 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
292 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
293 /* Invalidate any pending reference in QEMU for this virtual address */
294 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
295 tlb->pte0 = pte0;
296 tlb->pte1 = pte1;
297 tlb->EPN = EPN;
298 /* Store last way for LRU mechanism */
299 env->last_way = way;
302 static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
303 target_ulong eaddr, int rw, int access_type)
305 ppc6xx_tlb_t *tlb;
306 int nr, best, way;
307 int ret;
309 best = -1;
310 ret = -1; /* No TLB found */
311 for (way = 0; way < env->nb_ways; way++) {
312 nr = ppc6xx_tlb_getnum(env, eaddr, way,
313 access_type == ACCESS_CODE ? 1 : 0);
314 tlb = &env->tlb.tlb6[nr];
315 /* This test "emulates" the PTE index match for hardware TLBs */
316 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
317 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
318 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
319 pte_is_valid(tlb->pte0) ? "valid" : "inval",
320 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
321 continue;
323 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
324 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
325 pte_is_valid(tlb->pte0) ? "valid" : "inval",
326 tlb->EPN, eaddr, tlb->pte1,
327 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
328 switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
329 case -3:
330 /* TLB inconsistency */
331 return -1;
332 case -2:
333 /* Access violation */
334 ret = -2;
335 best = nr;
336 break;
337 case -1:
338 default:
339 /* No match */
340 break;
341 case 0:
342 /* access granted */
343 /* XXX: we should go on looping to check all TLBs consistency
344 * but we can speed-up the whole thing as the
345 * result would be undefined if TLBs are not consistent.
347 ret = 0;
348 best = nr;
349 goto done;
352 if (best != -1) {
353 done:
354 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
355 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
356 /* Update page flags */
357 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
360 return ret;
363 /* Perform BAT hit & translation */
364 static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
365 int *validp, int *protp, target_ulong *BATu,
366 target_ulong *BATl)
368 target_ulong bl;
369 int pp, valid, prot;
371 bl = (*BATu & 0x00001FFC) << 15;
372 valid = 0;
373 prot = 0;
374 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
375 ((msr_pr != 0) && (*BATu & 0x00000001))) {
376 valid = 1;
377 pp = *BATl & 0x00000003;
378 if (pp != 0) {
379 prot = PAGE_READ | PAGE_EXEC;
380 if (pp == 0x2) {
381 prot |= PAGE_WRITE;
385 *blp = bl;
386 *validp = valid;
387 *protp = prot;
390 static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
391 target_ulong virtual, int rw, int type)
393 target_ulong *BATlt, *BATut, *BATu, *BATl;
394 target_ulong BEPIl, BEPIu, bl;
395 int i, valid, prot;
396 int ret = -1;
398 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
399 type == ACCESS_CODE ? 'I' : 'D', virtual);
400 switch (type) {
401 case ACCESS_CODE:
402 BATlt = env->IBAT[1];
403 BATut = env->IBAT[0];
404 break;
405 default:
406 BATlt = env->DBAT[1];
407 BATut = env->DBAT[0];
408 break;
410 for (i = 0; i < env->nb_BATs; i++) {
411 BATu = &BATut[i];
412 BATl = &BATlt[i];
413 BEPIu = *BATu & 0xF0000000;
414 BEPIl = *BATu & 0x0FFE0000;
415 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
416 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
417 " BATl " TARGET_FMT_lx "\n", __func__,
418 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
419 if ((virtual & 0xF0000000) == BEPIu &&
420 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
421 /* BAT matches */
422 if (valid != 0) {
423 /* Get physical address */
424 ctx->raddr = (*BATl & 0xF0000000) |
425 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
426 (virtual & 0x0001F000);
427 /* Compute access rights */
428 ctx->prot = prot;
429 ret = check_prot(ctx->prot, rw, type);
430 if (ret == 0) {
431 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
432 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
433 ctx->prot & PAGE_WRITE ? 'W' : '-');
435 break;
439 if (ret < 0) {
440 #if defined(DEBUG_BATS)
441 if (qemu_log_enabled()) {
442 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
443 for (i = 0; i < 4; i++) {
444 BATu = &BATut[i];
445 BATl = &BATlt[i];
446 BEPIu = *BATu & 0xF0000000;
447 BEPIl = *BATu & 0x0FFE0000;
448 bl = (*BATu & 0x00001FFC) << 15;
449 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
450 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
451 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
452 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
453 *BATu, *BATl, BEPIu, BEPIl, bl);
456 #endif
458 /* No hit */
459 return ret;
462 /* Perform segment based translation */
463 static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
464 target_ulong eaddr, int rw, int type)
466 hwaddr hash;
467 target_ulong vsid;
468 int ds, pr, target_page_bits;
469 int ret;
470 target_ulong sr, pgidx;
472 pr = msr_pr;
473 ctx->eaddr = eaddr;
475 sr = env->sr[eaddr >> 28];
476 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
477 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
478 ds = sr & 0x80000000 ? 1 : 0;
479 ctx->nx = sr & 0x10000000 ? 1 : 0;
480 vsid = sr & 0x00FFFFFF;
481 target_page_bits = TARGET_PAGE_BITS;
482 qemu_log_mask(CPU_LOG_MMU,
483 "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
484 " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
485 " ir=%d dr=%d pr=%d %d t=%d\n",
486 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
487 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
488 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
489 hash = vsid ^ pgidx;
490 ctx->ptem = (vsid << 7) | (pgidx >> 10);
492 qemu_log_mask(CPU_LOG_MMU,
493 "pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
494 ctx->key, ds, ctx->nx, vsid);
495 ret = -1;
496 if (!ds) {
497 /* Check if instruction fetch is allowed, if needed */
498 if (type != ACCESS_CODE || ctx->nx == 0) {
499 /* Page address translation */
500 qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
501 " htab_mask " TARGET_FMT_plx
502 " hash " TARGET_FMT_plx "\n",
503 env->htab_base, env->htab_mask, hash);
504 ctx->hash[0] = hash;
505 ctx->hash[1] = ~hash;
507 /* Initialize real address with an invalid value */
508 ctx->raddr = (hwaddr)-1ULL;
509 /* Software TLB search */
510 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
511 #if defined(DUMP_PAGE_TABLES)
512 if (qemu_log_mask(CPU_LOG_MMU)) {
513 hwaddr curaddr;
514 uint32_t a0, a1, a2, a3;
516 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
517 "\n", sdr, mask + 0x80);
518 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
519 curaddr += 16) {
520 a0 = ldl_phys(curaddr);
521 a1 = ldl_phys(curaddr + 4);
522 a2 = ldl_phys(curaddr + 8);
523 a3 = ldl_phys(curaddr + 12);
524 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
525 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
526 curaddr, a0, a1, a2, a3);
530 #endif
531 } else {
532 qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
533 ret = -3;
535 } else {
536 target_ulong sr;
538 qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
539 /* Direct-store segment : absolutely *BUGGY* for now */
541 /* Direct-store implies a 32-bit MMU.
542 * Check the Segment Register's bus unit ID (BUID).
544 sr = env->sr[eaddr >> 28];
545 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
546 /* Memory-forced I/O controller interface access */
547 /* If T=1 and BUID=x'07F', the 601 performs a memory access
548 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
550 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
551 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
552 return 0;
555 switch (type) {
556 case ACCESS_INT:
557 /* Integer load/store : only access allowed */
558 break;
559 case ACCESS_CODE:
560 /* No code fetch is allowed in direct-store areas */
561 return -4;
562 case ACCESS_FLOAT:
563 /* Floating point load/store */
564 return -4;
565 case ACCESS_RES:
566 /* lwarx, ldarx or srwcx. */
567 return -4;
568 case ACCESS_CACHE:
569 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
570 /* Should make the instruction do no-op.
571 * As it already do no-op, it's quite easy :-)
573 ctx->raddr = eaddr;
574 return 0;
575 case ACCESS_EXT:
576 /* eciwx or ecowx */
577 return -4;
578 default:
579 qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need "
580 "address translation\n");
581 return -4;
583 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
584 ctx->raddr = eaddr;
585 ret = 2;
586 } else {
587 ret = -2;
591 return ret;
594 /* Generic TLB check function for embedded PowerPC implementations */
595 static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
596 hwaddr *raddrp,
597 target_ulong address, uint32_t pid, int ext,
598 int i)
600 target_ulong mask;
602 /* Check valid flag */
603 if (!(tlb->prot & PAGE_VALID)) {
604 return -1;
606 mask = ~(tlb->size - 1);
607 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
608 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
609 mask, (uint32_t)tlb->PID, tlb->prot);
610 /* Check PID */
611 if (tlb->PID != 0 && tlb->PID != pid) {
612 return -1;
614 /* Check effective address */
615 if ((address & mask) != tlb->EPN) {
616 return -1;
618 *raddrp = (tlb->RPN & mask) | (address & ~mask);
619 if (ext) {
620 /* Extend the physical address to 36 bits */
621 *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
624 return 0;
627 /* Generic TLB search function for PowerPC embedded implementations */
628 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
629 uint32_t pid)
631 ppcemb_tlb_t *tlb;
632 hwaddr raddr;
633 int i, ret;
635 /* Default return value is no match */
636 ret = -1;
637 for (i = 0; i < env->nb_tlb; i++) {
638 tlb = &env->tlb.tlbe[i];
639 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
640 ret = i;
641 break;
645 return ret;
648 /* Helpers specific to PowerPC 40x implementations */
649 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
651 PowerPCCPU *cpu = ppc_env_get_cpu(env);
652 ppcemb_tlb_t *tlb;
653 int i;
655 for (i = 0; i < env->nb_tlb; i++) {
656 tlb = &env->tlb.tlbe[i];
657 tlb->prot &= ~PAGE_VALID;
659 tlb_flush(CPU(cpu), 1);
662 static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
663 target_ulong address, int rw,
664 int access_type)
666 ppcemb_tlb_t *tlb;
667 hwaddr raddr;
668 int i, ret, zsel, zpr, pr;
670 ret = -1;
671 raddr = (hwaddr)-1ULL;
672 pr = msr_pr;
673 for (i = 0; i < env->nb_tlb; i++) {
674 tlb = &env->tlb.tlbe[i];
675 if (ppcemb_tlb_check(env, tlb, &raddr, address,
676 env->spr[SPR_40x_PID], 0, i) < 0) {
677 continue;
679 zsel = (tlb->attr >> 4) & 0xF;
680 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
681 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
682 __func__, i, zsel, zpr, rw, tlb->attr);
683 /* Check execute enable bit */
684 switch (zpr) {
685 case 0x2:
686 if (pr != 0) {
687 goto check_perms;
689 /* No break here */
690 case 0x3:
691 /* All accesses granted */
692 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
693 ret = 0;
694 break;
695 case 0x0:
696 if (pr != 0) {
697 /* Raise Zone protection fault. */
698 env->spr[SPR_40x_ESR] = 1 << 22;
699 ctx->prot = 0;
700 ret = -2;
701 break;
703 /* No break here */
704 case 0x1:
705 check_perms:
706 /* Check from TLB entry */
707 ctx->prot = tlb->prot;
708 ret = check_prot(ctx->prot, rw, access_type);
709 if (ret == -2) {
710 env->spr[SPR_40x_ESR] = 0;
712 break;
714 if (ret >= 0) {
715 ctx->raddr = raddr;
716 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
717 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
718 ret);
719 return 0;
722 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
723 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
725 return ret;
728 void store_40x_sler(CPUPPCState *env, uint32_t val)
730 PowerPCCPU *cpu = ppc_env_get_cpu(env);
732 /* XXX: TO BE FIXED */
733 if (val != 0x00000000) {
734 cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
736 env->spr[SPR_405_SLER] = val;
739 static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
740 hwaddr *raddr, int *prot,
741 target_ulong address, int rw,
742 int access_type, int i)
744 int ret, prot2;
746 if (ppcemb_tlb_check(env, tlb, raddr, address,
747 env->spr[SPR_BOOKE_PID],
748 !env->nb_pids, i) >= 0) {
749 goto found_tlb;
752 if (env->spr[SPR_BOOKE_PID1] &&
753 ppcemb_tlb_check(env, tlb, raddr, address,
754 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
755 goto found_tlb;
758 if (env->spr[SPR_BOOKE_PID2] &&
759 ppcemb_tlb_check(env, tlb, raddr, address,
760 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
761 goto found_tlb;
764 LOG_SWTLB("%s: TLB entry not found\n", __func__);
765 return -1;
767 found_tlb:
769 if (msr_pr != 0) {
770 prot2 = tlb->prot & 0xF;
771 } else {
772 prot2 = (tlb->prot >> 4) & 0xF;
775 /* Check the address space */
776 if (access_type == ACCESS_CODE) {
777 if (msr_ir != (tlb->attr & 1)) {
778 LOG_SWTLB("%s: AS doesn't match\n", __func__);
779 return -1;
782 *prot = prot2;
783 if (prot2 & PAGE_EXEC) {
784 LOG_SWTLB("%s: good TLB!\n", __func__);
785 return 0;
788 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
789 ret = -3;
790 } else {
791 if (msr_dr != (tlb->attr & 1)) {
792 LOG_SWTLB("%s: AS doesn't match\n", __func__);
793 return -1;
796 *prot = prot2;
797 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
798 LOG_SWTLB("%s: found TLB!\n", __func__);
799 return 0;
802 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
803 ret = -2;
806 return ret;
809 static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
810 target_ulong address, int rw,
811 int access_type)
813 ppcemb_tlb_t *tlb;
814 hwaddr raddr;
815 int i, ret;
817 ret = -1;
818 raddr = (hwaddr)-1ULL;
819 for (i = 0; i < env->nb_tlb; i++) {
820 tlb = &env->tlb.tlbe[i];
821 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
822 access_type, i);
823 if (!ret) {
824 break;
828 if (ret >= 0) {
829 ctx->raddr = raddr;
830 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
831 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
832 ret);
833 } else {
834 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
835 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
838 return ret;
841 static void booke206_flush_tlb(CPUPPCState *env, int flags,
842 const int check_iprot)
844 PowerPCCPU *cpu = ppc_env_get_cpu(env);
845 int tlb_size;
846 int i, j;
847 ppcmas_tlb_t *tlb = env->tlb.tlbm;
849 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
850 if (flags & (1 << i)) {
851 tlb_size = booke206_tlb_size(env, i);
852 for (j = 0; j < tlb_size; j++) {
853 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
854 tlb[j].mas1 &= ~MAS1_VALID;
858 tlb += booke206_tlb_size(env, i);
861 tlb_flush(CPU(cpu), 1);
864 static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
865 ppcmas_tlb_t *tlb)
867 int tlbm_size;
869 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
871 return 1024ULL << tlbm_size;
874 /* TLB check function for MAS based SoftTLBs */
875 static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
876 hwaddr *raddrp, target_ulong address,
877 uint32_t pid)
879 hwaddr mask;
880 uint32_t tlb_pid;
882 if (!msr_cm) {
883 /* In 32bit mode we can only address 32bit EAs */
884 address = (uint32_t)address;
887 /* Check valid flag */
888 if (!(tlb->mas1 & MAS1_VALID)) {
889 return -1;
892 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
893 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
894 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
895 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
896 tlb->mas8);
898 /* Check PID */
899 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
900 if (tlb_pid != 0 && tlb_pid != pid) {
901 return -1;
904 /* Check effective address */
905 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
906 return -1;
909 if (raddrp) {
910 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
913 return 0;
916 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
917 hwaddr *raddr, int *prot,
918 target_ulong address, int rw,
919 int access_type)
921 int ret;
922 int prot2 = 0;
924 if (ppcmas_tlb_check(env, tlb, raddr, address,
925 env->spr[SPR_BOOKE_PID]) >= 0) {
926 goto found_tlb;
929 if (env->spr[SPR_BOOKE_PID1] &&
930 ppcmas_tlb_check(env, tlb, raddr, address,
931 env->spr[SPR_BOOKE_PID1]) >= 0) {
932 goto found_tlb;
935 if (env->spr[SPR_BOOKE_PID2] &&
936 ppcmas_tlb_check(env, tlb, raddr, address,
937 env->spr[SPR_BOOKE_PID2]) >= 0) {
938 goto found_tlb;
941 LOG_SWTLB("%s: TLB entry not found\n", __func__);
942 return -1;
944 found_tlb:
946 if (msr_pr != 0) {
947 if (tlb->mas7_3 & MAS3_UR) {
948 prot2 |= PAGE_READ;
950 if (tlb->mas7_3 & MAS3_UW) {
951 prot2 |= PAGE_WRITE;
953 if (tlb->mas7_3 & MAS3_UX) {
954 prot2 |= PAGE_EXEC;
956 } else {
957 if (tlb->mas7_3 & MAS3_SR) {
958 prot2 |= PAGE_READ;
960 if (tlb->mas7_3 & MAS3_SW) {
961 prot2 |= PAGE_WRITE;
963 if (tlb->mas7_3 & MAS3_SX) {
964 prot2 |= PAGE_EXEC;
968 /* Check the address space and permissions */
969 if (access_type == ACCESS_CODE) {
970 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
971 LOG_SWTLB("%s: AS doesn't match\n", __func__);
972 return -1;
975 *prot = prot2;
976 if (prot2 & PAGE_EXEC) {
977 LOG_SWTLB("%s: good TLB!\n", __func__);
978 return 0;
981 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
982 ret = -3;
983 } else {
984 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
985 LOG_SWTLB("%s: AS doesn't match\n", __func__);
986 return -1;
989 *prot = prot2;
990 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
991 LOG_SWTLB("%s: found TLB!\n", __func__);
992 return 0;
995 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
996 ret = -2;
999 return ret;
1002 static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1003 target_ulong address, int rw,
1004 int access_type)
1006 ppcmas_tlb_t *tlb;
1007 hwaddr raddr;
1008 int i, j, ret;
1010 ret = -1;
1011 raddr = (hwaddr)-1ULL;
1013 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1014 int ways = booke206_tlb_ways(env, i);
1016 for (j = 0; j < ways; j++) {
1017 tlb = booke206_get_tlbm(env, i, address, j);
1018 if (!tlb) {
1019 continue;
1021 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1022 rw, access_type);
1023 if (ret != -1) {
1024 goto found_tlb;
1029 found_tlb:
1031 if (ret >= 0) {
1032 ctx->raddr = raddr;
1033 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1034 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1035 ret);
1036 } else {
1037 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1038 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1041 return ret;
1044 static const char *book3e_tsize_to_str[32] = {
1045 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1046 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1047 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1048 "1T", "2T"
1051 static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1052 CPUPPCState *env)
1054 ppcemb_tlb_t *entry;
1055 int i;
1057 if (kvm_enabled() && !env->kvm_sw_tlb) {
1058 cpu_fprintf(f, "Cannot access KVM TLB\n");
1059 return;
1062 cpu_fprintf(f, "\nTLB:\n");
1063 cpu_fprintf(f, "Effective Physical Size PID Prot "
1064 "Attr\n");
1066 entry = &env->tlb.tlbe[0];
1067 for (i = 0; i < env->nb_tlb; i++, entry++) {
1068 hwaddr ea, pa;
1069 target_ulong mask;
1070 uint64_t size = (uint64_t)entry->size;
1071 char size_buf[20];
1073 /* Check valid flag */
1074 if (!(entry->prot & PAGE_VALID)) {
1075 continue;
1078 mask = ~(entry->size - 1);
1079 ea = entry->EPN & mask;
1080 pa = entry->RPN & mask;
1081 /* Extend the physical address to 36 bits */
1082 pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1083 size /= 1024;
1084 if (size >= 1024) {
1085 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1086 } else {
1087 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1089 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1090 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1091 entry->prot, entry->attr);
1096 static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1097 CPUPPCState *env, int tlbn, int offset,
1098 int tlbsize)
1100 ppcmas_tlb_t *entry;
1101 int i;
1103 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1104 cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
1105 " URWX WIMGE U0123\n");
1107 entry = &env->tlb.tlbm[offset];
1108 for (i = 0; i < tlbsize; i++, entry++) {
1109 hwaddr ea, pa, size;
1110 int tsize;
1112 if (!(entry->mas1 & MAS1_VALID)) {
1113 continue;
1116 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1117 size = 1024ULL << tsize;
1118 ea = entry->mas2 & ~(size - 1);
1119 pa = entry->mas7_3 & ~(size - 1);
1121 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1122 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1123 (uint64_t)ea, (uint64_t)pa,
1124 book3e_tsize_to_str[tsize],
1125 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1126 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1127 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1128 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1129 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1130 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1131 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1132 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1133 entry->mas2 & MAS2_W ? 'W' : '-',
1134 entry->mas2 & MAS2_I ? 'I' : '-',
1135 entry->mas2 & MAS2_M ? 'M' : '-',
1136 entry->mas2 & MAS2_G ? 'G' : '-',
1137 entry->mas2 & MAS2_E ? 'E' : '-',
1138 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1139 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1140 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1141 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1145 static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1146 CPUPPCState *env)
1148 int offset = 0;
1149 int i;
1151 if (kvm_enabled() && !env->kvm_sw_tlb) {
1152 cpu_fprintf(f, "Cannot access KVM TLB\n");
1153 return;
1156 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1157 int size = booke206_tlb_size(env, i);
1159 if (size == 0) {
1160 continue;
1163 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1164 offset += size;
1168 static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
1169 CPUPPCState *env, int type)
1171 target_ulong *BATlt, *BATut, *BATu, *BATl;
1172 target_ulong BEPIl, BEPIu, bl;
1173 int i;
1175 switch (type) {
1176 case ACCESS_CODE:
1177 BATlt = env->IBAT[1];
1178 BATut = env->IBAT[0];
1179 break;
1180 default:
1181 BATlt = env->DBAT[1];
1182 BATut = env->DBAT[0];
1183 break;
1186 for (i = 0; i < env->nb_BATs; i++) {
1187 BATu = &BATut[i];
1188 BATl = &BATlt[i];
1189 BEPIu = *BATu & 0xF0000000;
1190 BEPIl = *BATu & 0x0FFE0000;
1191 bl = (*BATu & 0x00001FFC) << 15;
1192 cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx
1193 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
1194 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
1195 type == ACCESS_CODE ? "code" : "data", i,
1196 *BATu, *BATl, BEPIu, BEPIl, bl);
1200 static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1201 CPUPPCState *env)
1203 ppc6xx_tlb_t *tlb;
1204 target_ulong sr;
1205 int type, way, entry, i;
1207 cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
1208 cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
1210 cpu_fprintf(f, "\nSegment registers:\n");
1211 for (i = 0; i < 32; i++) {
1212 sr = env->sr[i];
1213 if (sr & 0x80000000) {
1214 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1215 "CNTLR_SPEC=0x%05x\n", i,
1216 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1217 sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
1218 (uint32_t)(sr & 0xFFFFF));
1219 } else {
1220 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
1221 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1222 sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
1223 (uint32_t)(sr & 0x00FFFFFF));
1227 cpu_fprintf(f, "\nBATs:\n");
1228 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT);
1229 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE);
1231 if (env->id_tlbs != 1) {
1232 cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB"
1233 " for code and data\n");
1236 cpu_fprintf(f, "\nTLBs [EPN EPN + SIZE]\n");
1238 for (type = 0; type < 2; type++) {
1239 for (way = 0; way < env->nb_ways; way++) {
1240 for (entry = env->nb_tlb * type + env->tlb_per_way * way;
1241 entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
1242 entry++) {
1244 tlb = &env->tlb.tlb6[entry];
1245 cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s ["
1246 TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
1247 type ? "code" : "data", entry % env->nb_tlb,
1248 env->nb_tlb, way,
1249 pte_is_valid(tlb->pte0) ? "valid" : "inval",
1250 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
1256 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1258 switch (env->mmu_model) {
1259 case POWERPC_MMU_BOOKE:
1260 mmubooke_dump_mmu(f, cpu_fprintf, env);
1261 break;
1262 case POWERPC_MMU_BOOKE206:
1263 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1264 break;
1265 case POWERPC_MMU_SOFT_6xx:
1266 case POWERPC_MMU_SOFT_74xx:
1267 mmu6xx_dump_mmu(f, cpu_fprintf, env);
1268 break;
1269 #if defined(TARGET_PPC64)
1270 case POWERPC_MMU_64B:
1271 case POWERPC_MMU_2_03:
1272 case POWERPC_MMU_2_06:
1273 case POWERPC_MMU_2_06a:
1274 case POWERPC_MMU_2_07:
1275 case POWERPC_MMU_2_07a:
1276 dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
1277 break;
1278 #endif
1279 default:
1280 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1284 static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1285 target_ulong eaddr, int rw)
1287 int in_plb, ret;
1289 ctx->raddr = eaddr;
1290 ctx->prot = PAGE_READ | PAGE_EXEC;
1291 ret = 0;
1292 switch (env->mmu_model) {
1293 case POWERPC_MMU_SOFT_6xx:
1294 case POWERPC_MMU_SOFT_74xx:
1295 case POWERPC_MMU_SOFT_4xx:
1296 case POWERPC_MMU_REAL:
1297 case POWERPC_MMU_BOOKE:
1298 ctx->prot |= PAGE_WRITE;
1299 break;
1301 case POWERPC_MMU_SOFT_4xx_Z:
1302 if (unlikely(msr_pe != 0)) {
1303 /* 403 family add some particular protections,
1304 * using PBL/PBU registers for accesses with no translation.
1306 in_plb =
1307 /* Check PLB validity */
1308 (env->pb[0] < env->pb[1] &&
1309 /* and address in plb area */
1310 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1311 (env->pb[2] < env->pb[3] &&
1312 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1313 if (in_plb ^ msr_px) {
1314 /* Access in protected area */
1315 if (rw == 1) {
1316 /* Access is not allowed */
1317 ret = -2;
1319 } else {
1320 /* Read-write access is allowed */
1321 ctx->prot |= PAGE_WRITE;
1324 break;
1326 default:
1327 /* Caller's checks mean we should never get here for other models */
1328 abort();
1329 return -1;
1332 return ret;
1335 static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1336 target_ulong eaddr, int rw, int access_type)
1338 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1339 int ret = -1;
1340 bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1341 || (access_type != ACCESS_CODE && msr_dr == 0);
1343 #if 0
1344 qemu_log("%s\n", __func__);
1345 #endif
1347 switch (env->mmu_model) {
1348 case POWERPC_MMU_SOFT_6xx:
1349 case POWERPC_MMU_SOFT_74xx:
1350 if (real_mode) {
1351 ret = check_physical(env, ctx, eaddr, rw);
1352 } else {
1353 /* Try to find a BAT */
1354 if (env->nb_BATs != 0) {
1355 ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
1357 if (ret < 0) {
1358 /* We didn't match any BAT entry or don't have BATs */
1359 ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1362 break;
1364 case POWERPC_MMU_SOFT_4xx:
1365 case POWERPC_MMU_SOFT_4xx_Z:
1366 if (real_mode) {
1367 ret = check_physical(env, ctx, eaddr, rw);
1368 } else {
1369 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1370 rw, access_type);
1372 break;
1373 case POWERPC_MMU_BOOKE:
1374 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1375 rw, access_type);
1376 break;
1377 case POWERPC_MMU_BOOKE206:
1378 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1379 access_type);
1380 break;
1381 case POWERPC_MMU_MPC8xx:
1382 /* XXX: TODO */
1383 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1384 break;
1385 case POWERPC_MMU_REAL:
1386 if (real_mode) {
1387 ret = check_physical(env, ctx, eaddr, rw);
1388 } else {
1389 cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n");
1391 return -1;
1392 default:
1393 cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
1394 return -1;
1396 #if 0
1397 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1398 __func__, eaddr, ret, ctx->raddr);
1399 #endif
1401 return ret;
1404 hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
1406 PowerPCCPU *cpu = POWERPC_CPU(cs);
1407 CPUPPCState *env = &cpu->env;
1408 mmu_ctx_t ctx;
1410 switch (env->mmu_model) {
1411 #if defined(TARGET_PPC64)
1412 case POWERPC_MMU_64B:
1413 case POWERPC_MMU_2_03:
1414 case POWERPC_MMU_2_06:
1415 case POWERPC_MMU_2_06a:
1416 case POWERPC_MMU_2_07:
1417 case POWERPC_MMU_2_07a:
1418 return ppc_hash64_get_phys_page_debug(cpu, addr);
1419 #endif
1421 case POWERPC_MMU_32B:
1422 case POWERPC_MMU_601:
1423 return ppc_hash32_get_phys_page_debug(cpu, addr);
1425 default:
1429 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1431 /* Some MMUs have separate TLBs for code and data. If we only try an
1432 * ACCESS_INT, we may not be able to read instructions mapped by code
1433 * TLBs, so we also try a ACCESS_CODE.
1435 if (unlikely(get_physical_address(env, &ctx, addr, 0,
1436 ACCESS_CODE) != 0)) {
1437 return -1;
1441 return ctx.raddr & TARGET_PAGE_MASK;
1444 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1445 int rw)
1447 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1448 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1449 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1450 env->spr[SPR_BOOKE_MAS3] = 0;
1451 env->spr[SPR_BOOKE_MAS6] = 0;
1452 env->spr[SPR_BOOKE_MAS7] = 0;
1454 /* AS */
1455 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1456 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1457 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1460 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1461 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1463 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1464 case MAS4_TIDSELD_PID0:
1465 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1466 break;
1467 case MAS4_TIDSELD_PID1:
1468 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1469 break;
1470 case MAS4_TIDSELD_PID2:
1471 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1472 break;
1475 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1477 /* next victim logic */
1478 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1479 env->last_way++;
1480 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1481 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1484 /* Perform address translation */
1485 static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
1486 int rw, int mmu_idx)
1488 CPUState *cs = CPU(ppc_env_get_cpu(env));
1489 PowerPCCPU *cpu = POWERPC_CPU(cs);
1490 mmu_ctx_t ctx;
1491 int access_type;
1492 int ret = 0;
1494 if (rw == 2) {
1495 /* code access */
1496 rw = 0;
1497 access_type = ACCESS_CODE;
1498 } else {
1499 /* data access */
1500 access_type = env->access_type;
1502 ret = get_physical_address(env, &ctx, address, rw, access_type);
1503 if (ret == 0) {
1504 tlb_set_page(cs, address & TARGET_PAGE_MASK,
1505 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1506 mmu_idx, TARGET_PAGE_SIZE);
1507 ret = 0;
1508 } else if (ret < 0) {
1509 LOG_MMU_STATE(cs);
1510 if (access_type == ACCESS_CODE) {
1511 switch (ret) {
1512 case -1:
1513 /* No matches in page tables or TLB */
1514 switch (env->mmu_model) {
1515 case POWERPC_MMU_SOFT_6xx:
1516 cs->exception_index = POWERPC_EXCP_IFTLB;
1517 env->error_code = 1 << 18;
1518 env->spr[SPR_IMISS] = address;
1519 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1520 goto tlb_miss;
1521 case POWERPC_MMU_SOFT_74xx:
1522 cs->exception_index = POWERPC_EXCP_IFTLB;
1523 goto tlb_miss_74xx;
1524 case POWERPC_MMU_SOFT_4xx:
1525 case POWERPC_MMU_SOFT_4xx_Z:
1526 cs->exception_index = POWERPC_EXCP_ITLB;
1527 env->error_code = 0;
1528 env->spr[SPR_40x_DEAR] = address;
1529 env->spr[SPR_40x_ESR] = 0x00000000;
1530 break;
1531 case POWERPC_MMU_BOOKE206:
1532 booke206_update_mas_tlb_miss(env, address, rw);
1533 /* fall through */
1534 case POWERPC_MMU_BOOKE:
1535 cs->exception_index = POWERPC_EXCP_ITLB;
1536 env->error_code = 0;
1537 env->spr[SPR_BOOKE_DEAR] = address;
1538 return -1;
1539 case POWERPC_MMU_MPC8xx:
1540 /* XXX: TODO */
1541 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1542 break;
1543 case POWERPC_MMU_REAL:
1544 cpu_abort(cs, "PowerPC in real mode should never raise "
1545 "any MMU exceptions\n");
1546 return -1;
1547 default:
1548 cpu_abort(cs, "Unknown or invalid MMU model\n");
1549 return -1;
1551 break;
1552 case -2:
1553 /* Access rights violation */
1554 cs->exception_index = POWERPC_EXCP_ISI;
1555 env->error_code = 0x08000000;
1556 break;
1557 case -3:
1558 /* No execute protection violation */
1559 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1560 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1561 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1563 cs->exception_index = POWERPC_EXCP_ISI;
1564 env->error_code = 0x10000000;
1565 break;
1566 case -4:
1567 /* Direct store exception */
1568 /* No code fetch is allowed in direct-store areas */
1569 cs->exception_index = POWERPC_EXCP_ISI;
1570 env->error_code = 0x10000000;
1571 break;
1573 } else {
1574 switch (ret) {
1575 case -1:
1576 /* No matches in page tables or TLB */
1577 switch (env->mmu_model) {
1578 case POWERPC_MMU_SOFT_6xx:
1579 if (rw == 1) {
1580 cs->exception_index = POWERPC_EXCP_DSTLB;
1581 env->error_code = 1 << 16;
1582 } else {
1583 cs->exception_index = POWERPC_EXCP_DLTLB;
1584 env->error_code = 0;
1586 env->spr[SPR_DMISS] = address;
1587 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1588 tlb_miss:
1589 env->error_code |= ctx.key << 19;
1590 env->spr[SPR_HASH1] = env->htab_base +
1591 get_pteg_offset32(cpu, ctx.hash[0]);
1592 env->spr[SPR_HASH2] = env->htab_base +
1593 get_pteg_offset32(cpu, ctx.hash[1]);
1594 break;
1595 case POWERPC_MMU_SOFT_74xx:
1596 if (rw == 1) {
1597 cs->exception_index = POWERPC_EXCP_DSTLB;
1598 } else {
1599 cs->exception_index = POWERPC_EXCP_DLTLB;
1601 tlb_miss_74xx:
1602 /* Implement LRU algorithm */
1603 env->error_code = ctx.key << 19;
1604 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1605 ((env->last_way + 1) & (env->nb_ways - 1));
1606 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1607 break;
1608 case POWERPC_MMU_SOFT_4xx:
1609 case POWERPC_MMU_SOFT_4xx_Z:
1610 cs->exception_index = POWERPC_EXCP_DTLB;
1611 env->error_code = 0;
1612 env->spr[SPR_40x_DEAR] = address;
1613 if (rw) {
1614 env->spr[SPR_40x_ESR] = 0x00800000;
1615 } else {
1616 env->spr[SPR_40x_ESR] = 0x00000000;
1618 break;
1619 case POWERPC_MMU_MPC8xx:
1620 /* XXX: TODO */
1621 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1622 break;
1623 case POWERPC_MMU_BOOKE206:
1624 booke206_update_mas_tlb_miss(env, address, rw);
1625 /* fall through */
1626 case POWERPC_MMU_BOOKE:
1627 cs->exception_index = POWERPC_EXCP_DTLB;
1628 env->error_code = 0;
1629 env->spr[SPR_BOOKE_DEAR] = address;
1630 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1631 return -1;
1632 case POWERPC_MMU_REAL:
1633 cpu_abort(cs, "PowerPC in real mode should never raise "
1634 "any MMU exceptions\n");
1635 return -1;
1636 default:
1637 cpu_abort(cs, "Unknown or invalid MMU model\n");
1638 return -1;
1640 break;
1641 case -2:
1642 /* Access rights violation */
1643 cs->exception_index = POWERPC_EXCP_DSI;
1644 env->error_code = 0;
1645 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1646 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1647 env->spr[SPR_40x_DEAR] = address;
1648 if (rw) {
1649 env->spr[SPR_40x_ESR] |= 0x00800000;
1651 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1652 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1653 env->spr[SPR_BOOKE_DEAR] = address;
1654 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1655 } else {
1656 env->spr[SPR_DAR] = address;
1657 if (rw == 1) {
1658 env->spr[SPR_DSISR] = 0x0A000000;
1659 } else {
1660 env->spr[SPR_DSISR] = 0x08000000;
1663 break;
1664 case -4:
1665 /* Direct store exception */
1666 switch (access_type) {
1667 case ACCESS_FLOAT:
1668 /* Floating point load/store */
1669 cs->exception_index = POWERPC_EXCP_ALIGN;
1670 env->error_code = POWERPC_EXCP_ALIGN_FP;
1671 env->spr[SPR_DAR] = address;
1672 break;
1673 case ACCESS_RES:
1674 /* lwarx, ldarx or stwcx. */
1675 cs->exception_index = POWERPC_EXCP_DSI;
1676 env->error_code = 0;
1677 env->spr[SPR_DAR] = address;
1678 if (rw == 1) {
1679 env->spr[SPR_DSISR] = 0x06000000;
1680 } else {
1681 env->spr[SPR_DSISR] = 0x04000000;
1683 break;
1684 case ACCESS_EXT:
1685 /* eciwx or ecowx */
1686 cs->exception_index = POWERPC_EXCP_DSI;
1687 env->error_code = 0;
1688 env->spr[SPR_DAR] = address;
1689 if (rw == 1) {
1690 env->spr[SPR_DSISR] = 0x06100000;
1691 } else {
1692 env->spr[SPR_DSISR] = 0x04100000;
1694 break;
1695 default:
1696 printf("DSI: invalid exception (%d)\n", ret);
1697 cs->exception_index = POWERPC_EXCP_PROGRAM;
1698 env->error_code =
1699 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1700 env->spr[SPR_DAR] = address;
1701 break;
1703 break;
1706 #if 0
1707 printf("%s: set exception to %d %02x\n", __func__,
1708 cs->exception, env->error_code);
1709 #endif
1710 ret = 1;
1713 return ret;
1716 /*****************************************************************************/
1717 /* BATs management */
1718 #if !defined(FLUSH_ALL_TLBS)
1719 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1720 target_ulong mask)
1722 CPUState *cs = CPU(ppc_env_get_cpu(env));
1723 target_ulong base, end, page;
1725 base = BATu & ~0x0001FFFF;
1726 end = base + mask + 0x00020000;
1727 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1728 TARGET_FMT_lx ")\n", base, end, mask);
1729 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
1730 tlb_flush_page(cs, page);
1732 LOG_BATS("Flush done\n");
1734 #endif
1736 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1737 target_ulong value)
1739 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1740 nr, ul == 0 ? 'u' : 'l', value, env->nip);
1743 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1745 target_ulong mask;
1747 dump_store_bat(env, 'I', 0, nr, value);
1748 if (env->IBAT[0][nr] != value) {
1749 mask = (value << 15) & 0x0FFE0000UL;
1750 #if !defined(FLUSH_ALL_TLBS)
1751 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1752 #endif
1753 /* When storing valid upper BAT, mask BEPI and BRPN
1754 * and invalidate all TLBs covered by this BAT
1756 mask = (value << 15) & 0x0FFE0000UL;
1757 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1758 (value & ~0x0001FFFFUL & ~mask);
1759 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1760 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1761 #if !defined(FLUSH_ALL_TLBS)
1762 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1763 #else
1764 tlb_flush(env, 1);
1765 #endif
1769 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1771 dump_store_bat(env, 'I', 1, nr, value);
1772 env->IBAT[1][nr] = value;
1775 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1777 target_ulong mask;
1779 dump_store_bat(env, 'D', 0, nr, value);
1780 if (env->DBAT[0][nr] != value) {
1781 /* When storing valid upper BAT, mask BEPI and BRPN
1782 * and invalidate all TLBs covered by this BAT
1784 mask = (value << 15) & 0x0FFE0000UL;
1785 #if !defined(FLUSH_ALL_TLBS)
1786 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1787 #endif
1788 mask = (value << 15) & 0x0FFE0000UL;
1789 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1790 (value & ~0x0001FFFFUL & ~mask);
1791 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1792 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1793 #if !defined(FLUSH_ALL_TLBS)
1794 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1795 #else
1796 tlb_flush(env, 1);
1797 #endif
1801 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1803 dump_store_bat(env, 'D', 1, nr, value);
1804 env->DBAT[1][nr] = value;
1807 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
1809 target_ulong mask;
1810 #if defined(FLUSH_ALL_TLBS)
1811 int do_inval;
1812 #endif
1814 dump_store_bat(env, 'I', 0, nr, value);
1815 if (env->IBAT[0][nr] != value) {
1816 #if defined(FLUSH_ALL_TLBS)
1817 do_inval = 0;
1818 #endif
1819 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1820 if (env->IBAT[1][nr] & 0x40) {
1821 /* Invalidate BAT only if it is valid */
1822 #if !defined(FLUSH_ALL_TLBS)
1823 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1824 #else
1825 do_inval = 1;
1826 #endif
1828 /* When storing valid upper BAT, mask BEPI and BRPN
1829 * and invalidate all TLBs covered by this BAT
1831 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1832 (value & ~0x0001FFFFUL & ~mask);
1833 env->DBAT[0][nr] = env->IBAT[0][nr];
1834 if (env->IBAT[1][nr] & 0x40) {
1835 #if !defined(FLUSH_ALL_TLBS)
1836 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1837 #else
1838 do_inval = 1;
1839 #endif
1841 #if defined(FLUSH_ALL_TLBS)
1842 if (do_inval) {
1843 tlb_flush(env, 1);
1845 #endif
1849 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
1851 #if !defined(FLUSH_ALL_TLBS)
1852 target_ulong mask;
1853 #else
1854 int do_inval;
1855 #endif
1857 dump_store_bat(env, 'I', 1, nr, value);
1858 if (env->IBAT[1][nr] != value) {
1859 #if defined(FLUSH_ALL_TLBS)
1860 do_inval = 0;
1861 #endif
1862 if (env->IBAT[1][nr] & 0x40) {
1863 #if !defined(FLUSH_ALL_TLBS)
1864 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1865 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1866 #else
1867 do_inval = 1;
1868 #endif
1870 if (value & 0x40) {
1871 #if !defined(FLUSH_ALL_TLBS)
1872 mask = (value << 17) & 0x0FFE0000UL;
1873 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1874 #else
1875 do_inval = 1;
1876 #endif
1878 env->IBAT[1][nr] = value;
1879 env->DBAT[1][nr] = value;
1880 #if defined(FLUSH_ALL_TLBS)
1881 if (do_inval) {
1882 tlb_flush(env, 1);
1884 #endif
1888 /*****************************************************************************/
1889 /* TLB management */
1890 void ppc_tlb_invalidate_all(CPUPPCState *env)
1892 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1894 switch (env->mmu_model) {
1895 case POWERPC_MMU_SOFT_6xx:
1896 case POWERPC_MMU_SOFT_74xx:
1897 ppc6xx_tlb_invalidate_all(env);
1898 break;
1899 case POWERPC_MMU_SOFT_4xx:
1900 case POWERPC_MMU_SOFT_4xx_Z:
1901 ppc4xx_tlb_invalidate_all(env);
1902 break;
1903 case POWERPC_MMU_REAL:
1904 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1905 break;
1906 case POWERPC_MMU_MPC8xx:
1907 /* XXX: TODO */
1908 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1909 break;
1910 case POWERPC_MMU_BOOKE:
1911 tlb_flush(CPU(cpu), 1);
1912 break;
1913 case POWERPC_MMU_BOOKE206:
1914 booke206_flush_tlb(env, -1, 0);
1915 break;
1916 case POWERPC_MMU_32B:
1917 case POWERPC_MMU_601:
1918 #if defined(TARGET_PPC64)
1919 case POWERPC_MMU_64B:
1920 case POWERPC_MMU_2_03:
1921 case POWERPC_MMU_2_06:
1922 case POWERPC_MMU_2_06a:
1923 case POWERPC_MMU_2_07:
1924 case POWERPC_MMU_2_07a:
1925 #endif /* defined(TARGET_PPC64) */
1926 tlb_flush(CPU(cpu), 1);
1927 break;
1928 default:
1929 /* XXX: TODO */
1930 cpu_abort(CPU(cpu), "Unknown MMU model\n");
1931 break;
1935 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
1937 #if !defined(FLUSH_ALL_TLBS)
1938 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1939 CPUState *cs;
1941 addr &= TARGET_PAGE_MASK;
1942 switch (env->mmu_model) {
1943 case POWERPC_MMU_SOFT_6xx:
1944 case POWERPC_MMU_SOFT_74xx:
1945 ppc6xx_tlb_invalidate_virt(env, addr, 0);
1946 if (env->id_tlbs == 1) {
1947 ppc6xx_tlb_invalidate_virt(env, addr, 1);
1949 break;
1950 case POWERPC_MMU_32B:
1951 case POWERPC_MMU_601:
1952 /* tlbie invalidate TLBs for all segments */
1953 addr &= ~((target_ulong)-1ULL << 28);
1954 cs = CPU(cpu);
1955 /* XXX: this case should be optimized,
1956 * giving a mask to tlb_flush_page
1958 tlb_flush_page(cs, addr | (0x0 << 28));
1959 tlb_flush_page(cs, addr | (0x1 << 28));
1960 tlb_flush_page(cs, addr | (0x2 << 28));
1961 tlb_flush_page(cs, addr | (0x3 << 28));
1962 tlb_flush_page(cs, addr | (0x4 << 28));
1963 tlb_flush_page(cs, addr | (0x5 << 28));
1964 tlb_flush_page(cs, addr | (0x6 << 28));
1965 tlb_flush_page(cs, addr | (0x7 << 28));
1966 tlb_flush_page(cs, addr | (0x8 << 28));
1967 tlb_flush_page(cs, addr | (0x9 << 28));
1968 tlb_flush_page(cs, addr | (0xA << 28));
1969 tlb_flush_page(cs, addr | (0xB << 28));
1970 tlb_flush_page(cs, addr | (0xC << 28));
1971 tlb_flush_page(cs, addr | (0xD << 28));
1972 tlb_flush_page(cs, addr | (0xE << 28));
1973 tlb_flush_page(cs, addr | (0xF << 28));
1974 break;
1975 #if defined(TARGET_PPC64)
1976 case POWERPC_MMU_64B:
1977 case POWERPC_MMU_2_03:
1978 case POWERPC_MMU_2_06:
1979 case POWERPC_MMU_2_06a:
1980 case POWERPC_MMU_2_07:
1981 case POWERPC_MMU_2_07a:
1982 /* tlbie invalidate TLBs for all segments */
1983 /* XXX: given the fact that there are too many segments to invalidate,
1984 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
1985 * we just invalidate all TLBs
1987 tlb_flush(CPU(cpu), 1);
1988 break;
1989 #endif /* defined(TARGET_PPC64) */
1990 default:
1991 /* Should never reach here with other MMU models */
1992 assert(0);
1994 #else
1995 ppc_tlb_invalidate_all(env);
1996 #endif
1999 /*****************************************************************************/
2000 /* Special registers manipulation */
2001 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2003 qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
2004 assert(!env->external_htab);
2005 env->spr[SPR_SDR1] = value;
2006 #if defined(TARGET_PPC64)
2007 if (env->mmu_model & POWERPC_MMU_64) {
2008 target_ulong htabsize = value & SDR_64_HTABSIZE;
2010 if (htabsize > 28) {
2011 fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
2012 " stored in SDR1\n", htabsize);
2013 htabsize = 28;
2015 env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
2016 env->htab_base = value & SDR_64_HTABORG;
2017 } else
2018 #endif /* defined(TARGET_PPC64) */
2020 /* FIXME: Should check for valid HTABMASK values */
2021 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2022 env->htab_base = value & SDR_32_HTABORG;
2026 /* Segment registers load and store */
2027 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2029 #if defined(TARGET_PPC64)
2030 if (env->mmu_model & POWERPC_MMU_64) {
2031 /* XXX */
2032 return 0;
2034 #endif
2035 return env->sr[sr_num];
2038 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2040 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2042 qemu_log_mask(CPU_LOG_MMU,
2043 "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2044 (int)srnum, value, env->sr[srnum]);
2045 #if defined(TARGET_PPC64)
2046 if (env->mmu_model & POWERPC_MMU_64) {
2047 uint64_t esid, vsid;
2049 /* ESID = srnum */
2050 esid = ((uint64_t)(srnum & 0xf) << 28) | SLB_ESID_V;
2052 /* VSID = VSID */
2053 vsid = (value & 0xfffffff) << 12;
2054 /* flags = flags */
2055 vsid |= ((value >> 27) & 0xf) << 8;
2057 ppc_store_slb(cpu, srnum, esid, vsid);
2058 } else
2059 #endif
2060 if (env->sr[srnum] != value) {
2061 env->sr[srnum] = value;
2062 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2063 flusing the whole TLB. */
2064 #if !defined(FLUSH_ALL_TLBS) && 0
2066 target_ulong page, end;
2067 /* Invalidate 256 MB of virtual memory */
2068 page = (16 << 20) * srnum;
2069 end = page + (16 << 20);
2070 for (; page != end; page += TARGET_PAGE_SIZE) {
2071 tlb_flush_page(CPU(cpu), page);
2074 #else
2075 tlb_flush(CPU(cpu), 1);
2076 #endif
2080 /* TLB management */
2081 void helper_tlbia(CPUPPCState *env)
2083 ppc_tlb_invalidate_all(env);
2086 void helper_tlbie(CPUPPCState *env, target_ulong addr)
2088 ppc_tlb_invalidate_one(env, addr);
2091 void helper_tlbiva(CPUPPCState *env, target_ulong addr)
2093 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2095 /* tlbiva instruction only exists on BookE */
2096 assert(env->mmu_model == POWERPC_MMU_BOOKE);
2097 /* XXX: TODO */
2098 cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
2101 /* Software driven TLBs management */
2102 /* PowerPC 602/603 software TLB load instructions helpers */
2103 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2105 target_ulong RPN, CMP, EPN;
2106 int way;
2108 RPN = env->spr[SPR_RPA];
2109 if (is_code) {
2110 CMP = env->spr[SPR_ICMP];
2111 EPN = env->spr[SPR_IMISS];
2112 } else {
2113 CMP = env->spr[SPR_DCMP];
2114 EPN = env->spr[SPR_DMISS];
2116 way = (env->spr[SPR_SRR1] >> 17) & 1;
2117 (void)EPN; /* avoid a compiler warning */
2118 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2119 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2120 RPN, way);
2121 /* Store this TLB */
2122 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2123 way, is_code, CMP, RPN);
2126 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2128 do_6xx_tlb(env, EPN, 0);
2131 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2133 do_6xx_tlb(env, EPN, 1);
2136 /* PowerPC 74xx software TLB load instructions helpers */
2137 static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2139 target_ulong RPN, CMP, EPN;
2140 int way;
2142 RPN = env->spr[SPR_PTELO];
2143 CMP = env->spr[SPR_PTEHI];
2144 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2145 way = env->spr[SPR_TLBMISS] & 0x3;
2146 (void)EPN; /* avoid a compiler warning */
2147 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2148 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2149 RPN, way);
2150 /* Store this TLB */
2151 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2152 way, is_code, CMP, RPN);
2155 void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2157 do_74xx_tlb(env, EPN, 0);
2160 void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2162 do_74xx_tlb(env, EPN, 1);
2165 /*****************************************************************************/
2166 /* PowerPC 601 specific instructions (POWER bridge) */
2168 target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2170 mmu_ctx_t ctx;
2171 int nb_BATs;
2172 target_ulong ret = 0;
2174 /* We don't have to generate many instances of this instruction,
2175 * as rac is supervisor only.
2177 /* XXX: FIX THIS: Pretend we have no BAT */
2178 nb_BATs = env->nb_BATs;
2179 env->nb_BATs = 0;
2180 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2181 ret = ctx.raddr;
2183 env->nb_BATs = nb_BATs;
2184 return ret;
2187 static inline target_ulong booke_tlb_to_page_size(int size)
2189 return 1024 << (2 * size);
2192 static inline int booke_page_size_to_tlb(target_ulong page_size)
2194 int size;
2196 switch (page_size) {
2197 case 0x00000400UL:
2198 size = 0x0;
2199 break;
2200 case 0x00001000UL:
2201 size = 0x1;
2202 break;
2203 case 0x00004000UL:
2204 size = 0x2;
2205 break;
2206 case 0x00010000UL:
2207 size = 0x3;
2208 break;
2209 case 0x00040000UL:
2210 size = 0x4;
2211 break;
2212 case 0x00100000UL:
2213 size = 0x5;
2214 break;
2215 case 0x00400000UL:
2216 size = 0x6;
2217 break;
2218 case 0x01000000UL:
2219 size = 0x7;
2220 break;
2221 case 0x04000000UL:
2222 size = 0x8;
2223 break;
2224 case 0x10000000UL:
2225 size = 0x9;
2226 break;
2227 case 0x40000000UL:
2228 size = 0xA;
2229 break;
2230 #if defined(TARGET_PPC64)
2231 case 0x000100000000ULL:
2232 size = 0xB;
2233 break;
2234 case 0x000400000000ULL:
2235 size = 0xC;
2236 break;
2237 case 0x001000000000ULL:
2238 size = 0xD;
2239 break;
2240 case 0x004000000000ULL:
2241 size = 0xE;
2242 break;
2243 case 0x010000000000ULL:
2244 size = 0xF;
2245 break;
2246 #endif
2247 default:
2248 size = -1;
2249 break;
2252 return size;
2255 /* Helpers for 4xx TLB management */
2256 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2258 #define PPC4XX_TLBHI_V 0x00000040
2259 #define PPC4XX_TLBHI_E 0x00000020
2260 #define PPC4XX_TLBHI_SIZE_MIN 0
2261 #define PPC4XX_TLBHI_SIZE_MAX 7
2262 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2263 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2264 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2266 #define PPC4XX_TLBLO_EX 0x00000200
2267 #define PPC4XX_TLBLO_WR 0x00000100
2268 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2269 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2271 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2273 ppcemb_tlb_t *tlb;
2274 target_ulong ret;
2275 int size;
2277 entry &= PPC4XX_TLB_ENTRY_MASK;
2278 tlb = &env->tlb.tlbe[entry];
2279 ret = tlb->EPN;
2280 if (tlb->prot & PAGE_VALID) {
2281 ret |= PPC4XX_TLBHI_V;
2283 size = booke_page_size_to_tlb(tlb->size);
2284 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2285 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2287 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2288 env->spr[SPR_40x_PID] = tlb->PID;
2289 return ret;
2292 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2294 ppcemb_tlb_t *tlb;
2295 target_ulong ret;
2297 entry &= PPC4XX_TLB_ENTRY_MASK;
2298 tlb = &env->tlb.tlbe[entry];
2299 ret = tlb->RPN;
2300 if (tlb->prot & PAGE_EXEC) {
2301 ret |= PPC4XX_TLBLO_EX;
2303 if (tlb->prot & PAGE_WRITE) {
2304 ret |= PPC4XX_TLBLO_WR;
2306 return ret;
2309 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2310 target_ulong val)
2312 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2313 CPUState *cs = CPU(cpu);
2314 ppcemb_tlb_t *tlb;
2315 target_ulong page, end;
2317 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2318 val);
2319 entry &= PPC4XX_TLB_ENTRY_MASK;
2320 tlb = &env->tlb.tlbe[entry];
2321 /* Invalidate previous TLB (if it's valid) */
2322 if (tlb->prot & PAGE_VALID) {
2323 end = tlb->EPN + tlb->size;
2324 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2325 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2326 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2327 tlb_flush_page(cs, page);
2330 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2331 & PPC4XX_TLBHI_SIZE_MASK);
2332 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2333 * If this ever occurs, one should use the ppcemb target instead
2334 * of the ppc or ppc64 one
2336 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2337 cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
2338 "are not supported (%d)\n",
2339 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2341 tlb->EPN = val & ~(tlb->size - 1);
2342 if (val & PPC4XX_TLBHI_V) {
2343 tlb->prot |= PAGE_VALID;
2344 if (val & PPC4XX_TLBHI_E) {
2345 /* XXX: TO BE FIXED */
2346 cpu_abort(cs,
2347 "Little-endian TLB entries are not supported by now\n");
2349 } else {
2350 tlb->prot &= ~PAGE_VALID;
2352 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2353 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2354 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2355 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2356 tlb->prot & PAGE_READ ? 'r' : '-',
2357 tlb->prot & PAGE_WRITE ? 'w' : '-',
2358 tlb->prot & PAGE_EXEC ? 'x' : '-',
2359 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2360 /* Invalidate new TLB (if valid) */
2361 if (tlb->prot & PAGE_VALID) {
2362 end = tlb->EPN + tlb->size;
2363 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2364 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2365 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2366 tlb_flush_page(cs, page);
2371 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2372 target_ulong val)
2374 ppcemb_tlb_t *tlb;
2376 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2377 val);
2378 entry &= PPC4XX_TLB_ENTRY_MASK;
2379 tlb = &env->tlb.tlbe[entry];
2380 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2381 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2382 tlb->prot = PAGE_READ;
2383 if (val & PPC4XX_TLBLO_EX) {
2384 tlb->prot |= PAGE_EXEC;
2386 if (val & PPC4XX_TLBLO_WR) {
2387 tlb->prot |= PAGE_WRITE;
2389 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2390 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2391 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2392 tlb->prot & PAGE_READ ? 'r' : '-',
2393 tlb->prot & PAGE_WRITE ? 'w' : '-',
2394 tlb->prot & PAGE_EXEC ? 'x' : '-',
2395 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2398 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2400 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2403 /* PowerPC 440 TLB management */
2404 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2405 target_ulong value)
2407 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2408 ppcemb_tlb_t *tlb;
2409 target_ulong EPN, RPN, size;
2410 int do_flush_tlbs;
2412 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2413 __func__, word, (int)entry, value);
2414 do_flush_tlbs = 0;
2415 entry &= 0x3F;
2416 tlb = &env->tlb.tlbe[entry];
2417 switch (word) {
2418 default:
2419 /* Just here to please gcc */
2420 case 0:
2421 EPN = value & 0xFFFFFC00;
2422 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2423 do_flush_tlbs = 1;
2425 tlb->EPN = EPN;
2426 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2427 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2428 do_flush_tlbs = 1;
2430 tlb->size = size;
2431 tlb->attr &= ~0x1;
2432 tlb->attr |= (value >> 8) & 1;
2433 if (value & 0x200) {
2434 tlb->prot |= PAGE_VALID;
2435 } else {
2436 if (tlb->prot & PAGE_VALID) {
2437 tlb->prot &= ~PAGE_VALID;
2438 do_flush_tlbs = 1;
2441 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2442 if (do_flush_tlbs) {
2443 tlb_flush(CPU(cpu), 1);
2445 break;
2446 case 1:
2447 RPN = value & 0xFFFFFC0F;
2448 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2449 tlb_flush(CPU(cpu), 1);
2451 tlb->RPN = RPN;
2452 break;
2453 case 2:
2454 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2455 tlb->prot = tlb->prot & PAGE_VALID;
2456 if (value & 0x1) {
2457 tlb->prot |= PAGE_READ << 4;
2459 if (value & 0x2) {
2460 tlb->prot |= PAGE_WRITE << 4;
2462 if (value & 0x4) {
2463 tlb->prot |= PAGE_EXEC << 4;
2465 if (value & 0x8) {
2466 tlb->prot |= PAGE_READ;
2468 if (value & 0x10) {
2469 tlb->prot |= PAGE_WRITE;
2471 if (value & 0x20) {
2472 tlb->prot |= PAGE_EXEC;
2474 break;
2478 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2479 target_ulong entry)
2481 ppcemb_tlb_t *tlb;
2482 target_ulong ret;
2483 int size;
2485 entry &= 0x3F;
2486 tlb = &env->tlb.tlbe[entry];
2487 switch (word) {
2488 default:
2489 /* Just here to please gcc */
2490 case 0:
2491 ret = tlb->EPN;
2492 size = booke_page_size_to_tlb(tlb->size);
2493 if (size < 0 || size > 0xF) {
2494 size = 1;
2496 ret |= size << 4;
2497 if (tlb->attr & 0x1) {
2498 ret |= 0x100;
2500 if (tlb->prot & PAGE_VALID) {
2501 ret |= 0x200;
2503 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2504 env->spr[SPR_440_MMUCR] |= tlb->PID;
2505 break;
2506 case 1:
2507 ret = tlb->RPN;
2508 break;
2509 case 2:
2510 ret = tlb->attr & ~0x1;
2511 if (tlb->prot & (PAGE_READ << 4)) {
2512 ret |= 0x1;
2514 if (tlb->prot & (PAGE_WRITE << 4)) {
2515 ret |= 0x2;
2517 if (tlb->prot & (PAGE_EXEC << 4)) {
2518 ret |= 0x4;
2520 if (tlb->prot & PAGE_READ) {
2521 ret |= 0x8;
2523 if (tlb->prot & PAGE_WRITE) {
2524 ret |= 0x10;
2526 if (tlb->prot & PAGE_EXEC) {
2527 ret |= 0x20;
2529 break;
2531 return ret;
2534 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2536 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2539 /* PowerPC BookE 2.06 TLB management */
2541 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2543 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2544 uint32_t tlbncfg = 0;
2545 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2546 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2547 int tlb;
2549 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2550 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2552 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2553 cpu_abort(CPU(cpu), "we don't support HES yet\n");
2556 return booke206_get_tlbm(env, tlb, ea, esel);
2559 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2561 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2563 env->spr[pidn] = pid;
2564 /* changing PIDs mean we're in a different address space now */
2565 tlb_flush(CPU(cpu), 1);
2568 void helper_booke206_tlbwe(CPUPPCState *env)
2570 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2571 uint32_t tlbncfg, tlbn;
2572 ppcmas_tlb_t *tlb;
2573 uint32_t size_tlb, size_ps;
2574 target_ulong mask;
2577 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2578 case MAS0_WQ_ALWAYS:
2579 /* good to go, write that entry */
2580 break;
2581 case MAS0_WQ_COND:
2582 /* XXX check if reserved */
2583 if (0) {
2584 return;
2586 break;
2587 case MAS0_WQ_CLR_RSRV:
2588 /* XXX clear entry */
2589 return;
2590 default:
2591 /* no idea what to do */
2592 return;
2595 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2596 !msr_gs) {
2597 /* XXX we don't support direct LRAT setting yet */
2598 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2599 return;
2602 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2603 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2605 tlb = booke206_cur_tlb(env);
2607 if (!tlb) {
2608 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2609 POWERPC_EXCP_INVAL |
2610 POWERPC_EXCP_INVAL_INVAL);
2613 /* check that we support the targeted size */
2614 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2615 size_ps = booke206_tlbnps(env, tlbn);
2616 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2617 !(size_ps & (1 << size_tlb))) {
2618 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2619 POWERPC_EXCP_INVAL |
2620 POWERPC_EXCP_INVAL_INVAL);
2623 if (msr_gs) {
2624 cpu_abort(CPU(cpu), "missing HV implementation\n");
2626 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2627 env->spr[SPR_BOOKE_MAS3];
2628 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2630 /* MAV 1.0 only */
2631 if (!(tlbncfg & TLBnCFG_AVAIL)) {
2632 /* force !AVAIL TLB entries to correct page size */
2633 tlb->mas1 &= ~MAS1_TSIZE_MASK;
2634 /* XXX can be configured in MMUCSR0 */
2635 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2638 /* Make a mask from TLB size to discard invalid bits in EPN field */
2639 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2640 /* Add a mask for page attributes */
2641 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2643 if (!msr_cm) {
2644 /* Executing a tlbwe instruction in 32-bit mode will set
2645 * bits 0:31 of the TLB EPN field to zero.
2647 mask &= 0xffffffff;
2650 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
2652 if (!(tlbncfg & TLBnCFG_IPROT)) {
2653 /* no IPROT supported by TLB */
2654 tlb->mas1 &= ~MAS1_IPROT;
2657 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
2658 tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
2659 } else {
2660 tlb_flush(CPU(cpu), 1);
2664 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2666 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2667 int way = booke206_tlbm_to_way(env, tlb);
2669 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2670 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2671 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2673 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2674 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2675 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2676 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2679 void helper_booke206_tlbre(CPUPPCState *env)
2681 ppcmas_tlb_t *tlb = NULL;
2683 tlb = booke206_cur_tlb(env);
2684 if (!tlb) {
2685 env->spr[SPR_BOOKE_MAS1] = 0;
2686 } else {
2687 booke206_tlb_to_mas(env, tlb);
2691 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
2693 ppcmas_tlb_t *tlb = NULL;
2694 int i, j;
2695 hwaddr raddr;
2696 uint32_t spid, sas;
2698 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2699 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2701 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2702 int ways = booke206_tlb_ways(env, i);
2704 for (j = 0; j < ways; j++) {
2705 tlb = booke206_get_tlbm(env, i, address, j);
2707 if (!tlb) {
2708 continue;
2711 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2712 continue;
2715 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2716 continue;
2719 booke206_tlb_to_mas(env, tlb);
2720 return;
2724 /* no entry found, fill with defaults */
2725 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2726 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2727 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2728 env->spr[SPR_BOOKE_MAS3] = 0;
2729 env->spr[SPR_BOOKE_MAS7] = 0;
2731 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2732 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2735 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2736 << MAS1_TID_SHIFT;
2738 /* next victim logic */
2739 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2740 env->last_way++;
2741 env->last_way &= booke206_tlb_ways(env, 0) - 1;
2742 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2745 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2746 uint32_t ea)
2748 int i;
2749 int ways = booke206_tlb_ways(env, tlbn);
2750 target_ulong mask;
2752 for (i = 0; i < ways; i++) {
2753 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2754 if (!tlb) {
2755 continue;
2757 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2758 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2759 !(tlb->mas1 & MAS1_IPROT)) {
2760 tlb->mas1 &= ~MAS1_VALID;
2765 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
2767 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2769 if (address & 0x4) {
2770 /* flush all entries */
2771 if (address & 0x8) {
2772 /* flush all of TLB1 */
2773 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2774 } else {
2775 /* flush all of TLB0 */
2776 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2778 return;
2781 if (address & 0x8) {
2782 /* flush TLB1 entries */
2783 booke206_invalidate_ea_tlb(env, 1, address);
2784 tlb_flush(CPU(cpu), 1);
2785 } else {
2786 /* flush TLB0 entries */
2787 booke206_invalidate_ea_tlb(env, 0, address);
2788 tlb_flush_page(CPU(cpu), address & MAS2_EPN_MASK);
2792 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
2794 /* XXX missing LPID handling */
2795 booke206_flush_tlb(env, -1, 1);
2798 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
2800 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2801 int i, j;
2802 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2803 ppcmas_tlb_t *tlb = env->tlb.tlbm;
2804 int tlb_size;
2806 /* XXX missing LPID handling */
2807 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2808 tlb_size = booke206_tlb_size(env, i);
2809 for (j = 0; j < tlb_size; j++) {
2810 if (!(tlb[j].mas1 & MAS1_IPROT) &&
2811 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2812 tlb[j].mas1 &= ~MAS1_VALID;
2815 tlb += booke206_tlb_size(env, i);
2817 tlb_flush(CPU(cpu), 1);
2820 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
2822 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2823 int i, j;
2824 ppcmas_tlb_t *tlb;
2825 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2826 int pid = tid >> MAS6_SPID_SHIFT;
2827 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2828 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
2829 /* XXX check for unsupported isize and raise an invalid opcode then */
2830 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
2831 /* XXX implement MAV2 handling */
2832 bool mav2 = false;
2834 /* XXX missing LPID handling */
2835 /* flush by pid and ea */
2836 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2837 int ways = booke206_tlb_ways(env, i);
2839 for (j = 0; j < ways; j++) {
2840 tlb = booke206_get_tlbm(env, i, address, j);
2841 if (!tlb) {
2842 continue;
2844 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
2845 (tlb->mas1 & MAS1_IPROT) ||
2846 ((tlb->mas1 & MAS1_IND) != ind) ||
2847 ((tlb->mas8 & MAS8_TGS) != sgs)) {
2848 continue;
2850 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
2851 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2852 continue;
2854 /* XXX e500mc doesn't match SAS, but other cores might */
2855 tlb->mas1 &= ~MAS1_VALID;
2858 tlb_flush(CPU(cpu), 1);
2861 void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
2863 int flags = 0;
2865 if (type & 2) {
2866 flags |= BOOKE206_FLUSH_TLB1;
2869 if (type & 4) {
2870 flags |= BOOKE206_FLUSH_TLB0;
2873 booke206_flush_tlb(env, flags, 1);
2877 /*****************************************************************************/
2879 /* try to fill the TLB and return an exception if error. If retaddr is
2880 NULL, it means that the function was called in C code (i.e. not
2881 from generated code or from helper.c) */
2882 /* XXX: fix it to restore all registers */
2883 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
2884 uintptr_t retaddr)
2886 PowerPCCPU *cpu = POWERPC_CPU(cs);
2887 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
2888 CPUPPCState *env = &cpu->env;
2889 int ret;
2891 if (pcc->handle_mmu_fault) {
2892 ret = pcc->handle_mmu_fault(cpu, addr, is_write, mmu_idx);
2893 } else {
2894 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
2896 if (unlikely(ret != 0)) {
2897 if (likely(retaddr)) {
2898 /* now we have a real cpu fault */
2899 cpu_restore_state(cs, retaddr);
2901 helper_raise_exception_err(env, cs->exception_index, env->error_code);