slirp: Factorizing address translation
[qemu/kevin.git] / target-ppc / mmu_helper.c
blobde4e286eee7f25900cadcfaa245588a0fc91f6df
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"
28 //#define DEBUG_MMU
29 //#define DEBUG_BATS
30 //#define DEBUG_SOFTWARE_TLB
31 //#define DUMP_PAGE_TABLES
32 //#define FLUSH_ALL_TLBS
34 #ifdef DEBUG_MMU
35 # define LOG_MMU_STATE(cpu) log_cpu_state_mask(CPU_LOG_MMU, (cpu), 0)
36 #else
37 # define LOG_MMU_STATE(cpu) do { } while (0)
38 #endif
40 #ifdef DEBUG_SOFTWARE_TLB
41 # define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
42 #else
43 # define LOG_SWTLB(...) do { } while (0)
44 #endif
46 #ifdef DEBUG_BATS
47 # define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
48 #else
49 # define LOG_BATS(...) do { } while (0)
50 #endif
52 /*****************************************************************************/
53 /* PowerPC MMU emulation */
55 /* Context used internally during MMU translations */
56 typedef struct mmu_ctx_t mmu_ctx_t;
57 struct mmu_ctx_t {
58 hwaddr raddr; /* Real address */
59 hwaddr eaddr; /* Effective address */
60 int prot; /* Protection bits */
61 hwaddr hash[2]; /* Pagetable hash values */
62 target_ulong ptem; /* Virtual segment ID | API */
63 int key; /* Access key */
64 int nx; /* Non-execute area */
67 /* Common routines used by software and hardware TLBs emulation */
68 static inline int pte_is_valid(target_ulong pte0)
70 return pte0 & 0x80000000 ? 1 : 0;
73 static inline void pte_invalidate(target_ulong *pte0)
75 *pte0 &= ~0x80000000;
78 #define PTE_PTEM_MASK 0x7FFFFFBF
79 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
81 static int pp_check(int key, int pp, int nx)
83 int access;
85 /* Compute access rights */
86 access = 0;
87 if (key == 0) {
88 switch (pp) {
89 case 0x0:
90 case 0x1:
91 case 0x2:
92 access |= PAGE_WRITE;
93 /* No break here */
94 case 0x3:
95 access |= PAGE_READ;
96 break;
98 } else {
99 switch (pp) {
100 case 0x0:
101 access = 0;
102 break;
103 case 0x1:
104 case 0x3:
105 access = PAGE_READ;
106 break;
107 case 0x2:
108 access = PAGE_READ | PAGE_WRITE;
109 break;
112 if (nx == 0) {
113 access |= PAGE_EXEC;
116 return access;
119 static int check_prot(int prot, int rw, int access_type)
121 int ret;
123 if (access_type == ACCESS_CODE) {
124 if (prot & PAGE_EXEC) {
125 ret = 0;
126 } else {
127 ret = -2;
129 } else if (rw) {
130 if (prot & PAGE_WRITE) {
131 ret = 0;
132 } else {
133 ret = -2;
135 } else {
136 if (prot & PAGE_READ) {
137 ret = 0;
138 } else {
139 ret = -2;
143 return ret;
146 static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
147 target_ulong pte1, int h, int rw, int type)
149 target_ulong ptem, mmask;
150 int access, ret, pteh, ptev, pp;
152 ret = -1;
153 /* Check validity and table match */
154 ptev = pte_is_valid(pte0);
155 pteh = (pte0 >> 6) & 1;
156 if (ptev && h == pteh) {
157 /* Check vsid & api */
158 ptem = pte0 & PTE_PTEM_MASK;
159 mmask = PTE_CHECK_MASK;
160 pp = pte1 & 0x00000003;
161 if (ptem == ctx->ptem) {
162 if (ctx->raddr != (hwaddr)-1ULL) {
163 /* all matches should have equal RPN, WIMG & PP */
164 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
165 qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
166 return -3;
169 /* Compute access rights */
170 access = pp_check(ctx->key, pp, ctx->nx);
171 /* Keep the matching PTE informations */
172 ctx->raddr = pte1;
173 ctx->prot = access;
174 ret = check_prot(ctx->prot, rw, type);
175 if (ret == 0) {
176 /* Access granted */
177 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
178 } else {
179 /* Access right violation */
180 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
185 return ret;
188 static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
189 int ret, int rw)
191 int store = 0;
193 /* Update page flags */
194 if (!(*pte1p & 0x00000100)) {
195 /* Update accessed flag */
196 *pte1p |= 0x00000100;
197 store = 1;
199 if (!(*pte1p & 0x00000080)) {
200 if (rw == 1 && ret == 0) {
201 /* Update changed flag */
202 *pte1p |= 0x00000080;
203 store = 1;
204 } else {
205 /* Force page fault for first write access */
206 ctx->prot &= ~PAGE_WRITE;
210 return store;
213 /* Software driven TLB helpers */
214 static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
215 int way, int is_code)
217 int nr;
219 /* Select TLB num in a way from address */
220 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
221 /* Select TLB way */
222 nr += env->tlb_per_way * way;
223 /* 6xx have separate TLBs for instructions and data */
224 if (is_code && env->id_tlbs == 1) {
225 nr += env->nb_tlb;
228 return nr;
231 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
233 PowerPCCPU *cpu = ppc_env_get_cpu(env);
234 ppc6xx_tlb_t *tlb;
235 int nr, max;
237 /* LOG_SWTLB("Invalidate all TLBs\n"); */
238 /* Invalidate all defined software TLB */
239 max = env->nb_tlb;
240 if (env->id_tlbs == 1) {
241 max *= 2;
243 for (nr = 0; nr < max; nr++) {
244 tlb = &env->tlb.tlb6[nr];
245 pte_invalidate(&tlb->pte0);
247 tlb_flush(CPU(cpu), 1);
250 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
251 target_ulong eaddr,
252 int is_code, int match_epn)
254 #if !defined(FLUSH_ALL_TLBS)
255 CPUState *cs = CPU(ppc_env_get_cpu(env));
256 ppc6xx_tlb_t *tlb;
257 int way, nr;
259 /* Invalidate ITLB + DTLB, all ways */
260 for (way = 0; way < env->nb_ways; way++) {
261 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
262 tlb = &env->tlb.tlb6[nr];
263 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
264 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
265 env->nb_tlb, eaddr);
266 pte_invalidate(&tlb->pte0);
267 tlb_flush_page(cs, tlb->EPN);
270 #else
271 /* XXX: PowerPC specification say this is valid as well */
272 ppc6xx_tlb_invalidate_all(env);
273 #endif
276 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
277 target_ulong eaddr, int is_code)
279 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
282 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
283 int is_code, target_ulong pte0, target_ulong pte1)
285 ppc6xx_tlb_t *tlb;
286 int nr;
288 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
289 tlb = &env->tlb.tlb6[nr];
290 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
291 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
292 /* Invalidate any pending reference in QEMU for this virtual address */
293 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
294 tlb->pte0 = pte0;
295 tlb->pte1 = pte1;
296 tlb->EPN = EPN;
297 /* Store last way for LRU mechanism */
298 env->last_way = way;
301 static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
302 target_ulong eaddr, int rw, int access_type)
304 ppc6xx_tlb_t *tlb;
305 int nr, best, way;
306 int ret;
308 best = -1;
309 ret = -1; /* No TLB found */
310 for (way = 0; way < env->nb_ways; way++) {
311 nr = ppc6xx_tlb_getnum(env, eaddr, way,
312 access_type == ACCESS_CODE ? 1 : 0);
313 tlb = &env->tlb.tlb6[nr];
314 /* This test "emulates" the PTE index match for hardware TLBs */
315 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
316 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
317 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
318 pte_is_valid(tlb->pte0) ? "valid" : "inval",
319 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
320 continue;
322 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
323 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
324 pte_is_valid(tlb->pte0) ? "valid" : "inval",
325 tlb->EPN, eaddr, tlb->pte1,
326 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
327 switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
328 case -3:
329 /* TLB inconsistency */
330 return -1;
331 case -2:
332 /* Access violation */
333 ret = -2;
334 best = nr;
335 break;
336 case -1:
337 default:
338 /* No match */
339 break;
340 case 0:
341 /* access granted */
342 /* XXX: we should go on looping to check all TLBs consistency
343 * but we can speed-up the whole thing as the
344 * result would be undefined if TLBs are not consistent.
346 ret = 0;
347 best = nr;
348 goto done;
351 if (best != -1) {
352 done:
353 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
354 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
355 /* Update page flags */
356 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
359 return ret;
362 /* Perform BAT hit & translation */
363 static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
364 int *validp, int *protp, target_ulong *BATu,
365 target_ulong *BATl)
367 target_ulong bl;
368 int pp, valid, prot;
370 bl = (*BATu & 0x00001FFC) << 15;
371 valid = 0;
372 prot = 0;
373 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
374 ((msr_pr != 0) && (*BATu & 0x00000001))) {
375 valid = 1;
376 pp = *BATl & 0x00000003;
377 if (pp != 0) {
378 prot = PAGE_READ | PAGE_EXEC;
379 if (pp == 0x2) {
380 prot |= PAGE_WRITE;
384 *blp = bl;
385 *validp = valid;
386 *protp = prot;
389 static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
390 target_ulong virtual, int rw, int type)
392 target_ulong *BATlt, *BATut, *BATu, *BATl;
393 target_ulong BEPIl, BEPIu, bl;
394 int i, valid, prot;
395 int ret = -1;
397 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
398 type == ACCESS_CODE ? 'I' : 'D', virtual);
399 switch (type) {
400 case ACCESS_CODE:
401 BATlt = env->IBAT[1];
402 BATut = env->IBAT[0];
403 break;
404 default:
405 BATlt = env->DBAT[1];
406 BATut = env->DBAT[0];
407 break;
409 for (i = 0; i < env->nb_BATs; i++) {
410 BATu = &BATut[i];
411 BATl = &BATlt[i];
412 BEPIu = *BATu & 0xF0000000;
413 BEPIl = *BATu & 0x0FFE0000;
414 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
415 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
416 " BATl " TARGET_FMT_lx "\n", __func__,
417 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
418 if ((virtual & 0xF0000000) == BEPIu &&
419 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
420 /* BAT matches */
421 if (valid != 0) {
422 /* Get physical address */
423 ctx->raddr = (*BATl & 0xF0000000) |
424 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
425 (virtual & 0x0001F000);
426 /* Compute access rights */
427 ctx->prot = prot;
428 ret = check_prot(ctx->prot, rw, type);
429 if (ret == 0) {
430 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
431 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
432 ctx->prot & PAGE_WRITE ? 'W' : '-');
434 break;
438 if (ret < 0) {
439 #if defined(DEBUG_BATS)
440 if (qemu_log_enabled()) {
441 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
442 for (i = 0; i < 4; i++) {
443 BATu = &BATut[i];
444 BATl = &BATlt[i];
445 BEPIu = *BATu & 0xF0000000;
446 BEPIl = *BATu & 0x0FFE0000;
447 bl = (*BATu & 0x00001FFC) << 15;
448 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
449 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
450 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
451 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
452 *BATu, *BATl, BEPIu, BEPIl, bl);
455 #endif
457 /* No hit */
458 return ret;
461 /* Perform segment based translation */
462 static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
463 target_ulong eaddr, int rw, int type)
465 hwaddr hash;
466 target_ulong vsid;
467 int ds, pr, target_page_bits;
468 int ret;
469 target_ulong sr, pgidx;
471 pr = msr_pr;
472 ctx->eaddr = eaddr;
474 sr = env->sr[eaddr >> 28];
475 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
476 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
477 ds = sr & 0x80000000 ? 1 : 0;
478 ctx->nx = sr & 0x10000000 ? 1 : 0;
479 vsid = sr & 0x00FFFFFF;
480 target_page_bits = TARGET_PAGE_BITS;
481 qemu_log_mask(CPU_LOG_MMU,
482 "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
483 " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
484 " ir=%d dr=%d pr=%d %d t=%d\n",
485 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
486 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
487 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
488 hash = vsid ^ pgidx;
489 ctx->ptem = (vsid << 7) | (pgidx >> 10);
491 qemu_log_mask(CPU_LOG_MMU,
492 "pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
493 ctx->key, ds, ctx->nx, vsid);
494 ret = -1;
495 if (!ds) {
496 /* Check if instruction fetch is allowed, if needed */
497 if (type != ACCESS_CODE || ctx->nx == 0) {
498 /* Page address translation */
499 qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
500 " htab_mask " TARGET_FMT_plx
501 " hash " TARGET_FMT_plx "\n",
502 env->htab_base, env->htab_mask, hash);
503 ctx->hash[0] = hash;
504 ctx->hash[1] = ~hash;
506 /* Initialize real address with an invalid value */
507 ctx->raddr = (hwaddr)-1ULL;
508 /* Software TLB search */
509 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
510 #if defined(DUMP_PAGE_TABLES)
511 if (qemu_log_mask(CPU_LOG_MMU)) {
512 hwaddr curaddr;
513 uint32_t a0, a1, a2, a3;
515 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
516 "\n", sdr, mask + 0x80);
517 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
518 curaddr += 16) {
519 a0 = ldl_phys(curaddr);
520 a1 = ldl_phys(curaddr + 4);
521 a2 = ldl_phys(curaddr + 8);
522 a3 = ldl_phys(curaddr + 12);
523 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
524 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
525 curaddr, a0, a1, a2, a3);
529 #endif
530 } else {
531 qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
532 ret = -3;
534 } else {
535 target_ulong sr;
537 qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
538 /* Direct-store segment : absolutely *BUGGY* for now */
540 /* Direct-store implies a 32-bit MMU.
541 * Check the Segment Register's bus unit ID (BUID).
543 sr = env->sr[eaddr >> 28];
544 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
545 /* Memory-forced I/O controller interface access */
546 /* If T=1 and BUID=x'07F', the 601 performs a memory access
547 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
549 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
550 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
551 return 0;
554 switch (type) {
555 case ACCESS_INT:
556 /* Integer load/store : only access allowed */
557 break;
558 case ACCESS_CODE:
559 /* No code fetch is allowed in direct-store areas */
560 return -4;
561 case ACCESS_FLOAT:
562 /* Floating point load/store */
563 return -4;
564 case ACCESS_RES:
565 /* lwarx, ldarx or srwcx. */
566 return -4;
567 case ACCESS_CACHE:
568 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
569 /* Should make the instruction do no-op.
570 * As it already do no-op, it's quite easy :-)
572 ctx->raddr = eaddr;
573 return 0;
574 case ACCESS_EXT:
575 /* eciwx or ecowx */
576 return -4;
577 default:
578 qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need "
579 "address translation\n");
580 return -4;
582 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
583 ctx->raddr = eaddr;
584 ret = 2;
585 } else {
586 ret = -2;
590 return ret;
593 /* Generic TLB check function for embedded PowerPC implementations */
594 static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
595 hwaddr *raddrp,
596 target_ulong address, uint32_t pid, int ext,
597 int i)
599 target_ulong mask;
601 /* Check valid flag */
602 if (!(tlb->prot & PAGE_VALID)) {
603 return -1;
605 mask = ~(tlb->size - 1);
606 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
607 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
608 mask, (uint32_t)tlb->PID, tlb->prot);
609 /* Check PID */
610 if (tlb->PID != 0 && tlb->PID != pid) {
611 return -1;
613 /* Check effective address */
614 if ((address & mask) != tlb->EPN) {
615 return -1;
617 *raddrp = (tlb->RPN & mask) | (address & ~mask);
618 if (ext) {
619 /* Extend the physical address to 36 bits */
620 *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
623 return 0;
626 /* Generic TLB search function for PowerPC embedded implementations */
627 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
628 uint32_t pid)
630 ppcemb_tlb_t *tlb;
631 hwaddr raddr;
632 int i, ret;
634 /* Default return value is no match */
635 ret = -1;
636 for (i = 0; i < env->nb_tlb; i++) {
637 tlb = &env->tlb.tlbe[i];
638 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
639 ret = i;
640 break;
644 return ret;
647 /* Helpers specific to PowerPC 40x implementations */
648 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
650 PowerPCCPU *cpu = ppc_env_get_cpu(env);
651 ppcemb_tlb_t *tlb;
652 int i;
654 for (i = 0; i < env->nb_tlb; i++) {
655 tlb = &env->tlb.tlbe[i];
656 tlb->prot &= ~PAGE_VALID;
658 tlb_flush(CPU(cpu), 1);
661 static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
662 target_ulong address, int rw,
663 int access_type)
665 ppcemb_tlb_t *tlb;
666 hwaddr raddr;
667 int i, ret, zsel, zpr, pr;
669 ret = -1;
670 raddr = (hwaddr)-1ULL;
671 pr = msr_pr;
672 for (i = 0; i < env->nb_tlb; i++) {
673 tlb = &env->tlb.tlbe[i];
674 if (ppcemb_tlb_check(env, tlb, &raddr, address,
675 env->spr[SPR_40x_PID], 0, i) < 0) {
676 continue;
678 zsel = (tlb->attr >> 4) & 0xF;
679 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
680 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
681 __func__, i, zsel, zpr, rw, tlb->attr);
682 /* Check execute enable bit */
683 switch (zpr) {
684 case 0x2:
685 if (pr != 0) {
686 goto check_perms;
688 /* No break here */
689 case 0x3:
690 /* All accesses granted */
691 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
692 ret = 0;
693 break;
694 case 0x0:
695 if (pr != 0) {
696 /* Raise Zone protection fault. */
697 env->spr[SPR_40x_ESR] = 1 << 22;
698 ctx->prot = 0;
699 ret = -2;
700 break;
702 /* No break here */
703 case 0x1:
704 check_perms:
705 /* Check from TLB entry */
706 ctx->prot = tlb->prot;
707 ret = check_prot(ctx->prot, rw, access_type);
708 if (ret == -2) {
709 env->spr[SPR_40x_ESR] = 0;
711 break;
713 if (ret >= 0) {
714 ctx->raddr = raddr;
715 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
716 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
717 ret);
718 return 0;
721 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
722 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
724 return ret;
727 void store_40x_sler(CPUPPCState *env, uint32_t val)
729 PowerPCCPU *cpu = ppc_env_get_cpu(env);
731 /* XXX: TO BE FIXED */
732 if (val != 0x00000000) {
733 cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
735 env->spr[SPR_405_SLER] = val;
738 static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
739 hwaddr *raddr, int *prot,
740 target_ulong address, int rw,
741 int access_type, int i)
743 int ret, prot2;
745 if (ppcemb_tlb_check(env, tlb, raddr, address,
746 env->spr[SPR_BOOKE_PID],
747 !env->nb_pids, i) >= 0) {
748 goto found_tlb;
751 if (env->spr[SPR_BOOKE_PID1] &&
752 ppcemb_tlb_check(env, tlb, raddr, address,
753 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
754 goto found_tlb;
757 if (env->spr[SPR_BOOKE_PID2] &&
758 ppcemb_tlb_check(env, tlb, raddr, address,
759 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
760 goto found_tlb;
763 LOG_SWTLB("%s: TLB entry not found\n", __func__);
764 return -1;
766 found_tlb:
768 if (msr_pr != 0) {
769 prot2 = tlb->prot & 0xF;
770 } else {
771 prot2 = (tlb->prot >> 4) & 0xF;
774 /* Check the address space */
775 if (access_type == ACCESS_CODE) {
776 if (msr_ir != (tlb->attr & 1)) {
777 LOG_SWTLB("%s: AS doesn't match\n", __func__);
778 return -1;
781 *prot = prot2;
782 if (prot2 & PAGE_EXEC) {
783 LOG_SWTLB("%s: good TLB!\n", __func__);
784 return 0;
787 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
788 ret = -3;
789 } else {
790 if (msr_dr != (tlb->attr & 1)) {
791 LOG_SWTLB("%s: AS doesn't match\n", __func__);
792 return -1;
795 *prot = prot2;
796 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
797 LOG_SWTLB("%s: found TLB!\n", __func__);
798 return 0;
801 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
802 ret = -2;
805 return ret;
808 static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
809 target_ulong address, int rw,
810 int access_type)
812 ppcemb_tlb_t *tlb;
813 hwaddr raddr;
814 int i, ret;
816 ret = -1;
817 raddr = (hwaddr)-1ULL;
818 for (i = 0; i < env->nb_tlb; i++) {
819 tlb = &env->tlb.tlbe[i];
820 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
821 access_type, i);
822 if (!ret) {
823 break;
827 if (ret >= 0) {
828 ctx->raddr = raddr;
829 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
830 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
831 ret);
832 } else {
833 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
834 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
837 return ret;
840 static void booke206_flush_tlb(CPUPPCState *env, int flags,
841 const int check_iprot)
843 PowerPCCPU *cpu = ppc_env_get_cpu(env);
844 int tlb_size;
845 int i, j;
846 ppcmas_tlb_t *tlb = env->tlb.tlbm;
848 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
849 if (flags & (1 << i)) {
850 tlb_size = booke206_tlb_size(env, i);
851 for (j = 0; j < tlb_size; j++) {
852 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
853 tlb[j].mas1 &= ~MAS1_VALID;
857 tlb += booke206_tlb_size(env, i);
860 tlb_flush(CPU(cpu), 1);
863 static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
864 ppcmas_tlb_t *tlb)
866 int tlbm_size;
868 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
870 return 1024ULL << tlbm_size;
873 /* TLB check function for MAS based SoftTLBs */
874 static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
875 hwaddr *raddrp, target_ulong address,
876 uint32_t pid)
878 hwaddr mask;
879 uint32_t tlb_pid;
881 if (!msr_cm) {
882 /* In 32bit mode we can only address 32bit EAs */
883 address = (uint32_t)address;
886 /* Check valid flag */
887 if (!(tlb->mas1 & MAS1_VALID)) {
888 return -1;
891 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
892 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
893 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
894 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
895 tlb->mas8);
897 /* Check PID */
898 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
899 if (tlb_pid != 0 && tlb_pid != pid) {
900 return -1;
903 /* Check effective address */
904 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
905 return -1;
908 if (raddrp) {
909 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
912 return 0;
915 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
916 hwaddr *raddr, int *prot,
917 target_ulong address, int rw,
918 int access_type)
920 int ret;
921 int prot2 = 0;
923 if (ppcmas_tlb_check(env, tlb, raddr, address,
924 env->spr[SPR_BOOKE_PID]) >= 0) {
925 goto found_tlb;
928 if (env->spr[SPR_BOOKE_PID1] &&
929 ppcmas_tlb_check(env, tlb, raddr, address,
930 env->spr[SPR_BOOKE_PID1]) >= 0) {
931 goto found_tlb;
934 if (env->spr[SPR_BOOKE_PID2] &&
935 ppcmas_tlb_check(env, tlb, raddr, address,
936 env->spr[SPR_BOOKE_PID2]) >= 0) {
937 goto found_tlb;
940 LOG_SWTLB("%s: TLB entry not found\n", __func__);
941 return -1;
943 found_tlb:
945 if (msr_pr != 0) {
946 if (tlb->mas7_3 & MAS3_UR) {
947 prot2 |= PAGE_READ;
949 if (tlb->mas7_3 & MAS3_UW) {
950 prot2 |= PAGE_WRITE;
952 if (tlb->mas7_3 & MAS3_UX) {
953 prot2 |= PAGE_EXEC;
955 } else {
956 if (tlb->mas7_3 & MAS3_SR) {
957 prot2 |= PAGE_READ;
959 if (tlb->mas7_3 & MAS3_SW) {
960 prot2 |= PAGE_WRITE;
962 if (tlb->mas7_3 & MAS3_SX) {
963 prot2 |= PAGE_EXEC;
967 /* Check the address space and permissions */
968 if (access_type == ACCESS_CODE) {
969 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
970 LOG_SWTLB("%s: AS doesn't match\n", __func__);
971 return -1;
974 *prot = prot2;
975 if (prot2 & PAGE_EXEC) {
976 LOG_SWTLB("%s: good TLB!\n", __func__);
977 return 0;
980 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
981 ret = -3;
982 } else {
983 if (msr_dr != ((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 ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
990 LOG_SWTLB("%s: found TLB!\n", __func__);
991 return 0;
994 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
995 ret = -2;
998 return ret;
1001 static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1002 target_ulong address, int rw,
1003 int access_type)
1005 ppcmas_tlb_t *tlb;
1006 hwaddr raddr;
1007 int i, j, ret;
1009 ret = -1;
1010 raddr = (hwaddr)-1ULL;
1012 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1013 int ways = booke206_tlb_ways(env, i);
1015 for (j = 0; j < ways; j++) {
1016 tlb = booke206_get_tlbm(env, i, address, j);
1017 if (!tlb) {
1018 continue;
1020 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1021 rw, access_type);
1022 if (ret != -1) {
1023 goto found_tlb;
1028 found_tlb:
1030 if (ret >= 0) {
1031 ctx->raddr = raddr;
1032 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1033 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1034 ret);
1035 } else {
1036 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1037 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1040 return ret;
1043 static const char *book3e_tsize_to_str[32] = {
1044 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1045 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1046 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1047 "1T", "2T"
1050 static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1051 CPUPPCState *env)
1053 ppcemb_tlb_t *entry;
1054 int i;
1056 if (kvm_enabled() && !env->kvm_sw_tlb) {
1057 cpu_fprintf(f, "Cannot access KVM TLB\n");
1058 return;
1061 cpu_fprintf(f, "\nTLB:\n");
1062 cpu_fprintf(f, "Effective Physical Size PID Prot "
1063 "Attr\n");
1065 entry = &env->tlb.tlbe[0];
1066 for (i = 0; i < env->nb_tlb; i++, entry++) {
1067 hwaddr ea, pa;
1068 target_ulong mask;
1069 uint64_t size = (uint64_t)entry->size;
1070 char size_buf[20];
1072 /* Check valid flag */
1073 if (!(entry->prot & PAGE_VALID)) {
1074 continue;
1077 mask = ~(entry->size - 1);
1078 ea = entry->EPN & mask;
1079 pa = entry->RPN & mask;
1080 /* Extend the physical address to 36 bits */
1081 pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1082 size /= 1024;
1083 if (size >= 1024) {
1084 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1085 } else {
1086 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1088 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1089 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1090 entry->prot, entry->attr);
1095 static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1096 CPUPPCState *env, int tlbn, int offset,
1097 int tlbsize)
1099 ppcmas_tlb_t *entry;
1100 int i;
1102 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1103 cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
1104 " URWX WIMGE U0123\n");
1106 entry = &env->tlb.tlbm[offset];
1107 for (i = 0; i < tlbsize; i++, entry++) {
1108 hwaddr ea, pa, size;
1109 int tsize;
1111 if (!(entry->mas1 & MAS1_VALID)) {
1112 continue;
1115 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1116 size = 1024ULL << tsize;
1117 ea = entry->mas2 & ~(size - 1);
1118 pa = entry->mas7_3 & ~(size - 1);
1120 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1121 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1122 (uint64_t)ea, (uint64_t)pa,
1123 book3e_tsize_to_str[tsize],
1124 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1125 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1126 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1127 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1128 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1129 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1130 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1131 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1132 entry->mas2 & MAS2_W ? 'W' : '-',
1133 entry->mas2 & MAS2_I ? 'I' : '-',
1134 entry->mas2 & MAS2_M ? 'M' : '-',
1135 entry->mas2 & MAS2_G ? 'G' : '-',
1136 entry->mas2 & MAS2_E ? 'E' : '-',
1137 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1138 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1139 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1140 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1144 static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1145 CPUPPCState *env)
1147 int offset = 0;
1148 int i;
1150 if (kvm_enabled() && !env->kvm_sw_tlb) {
1151 cpu_fprintf(f, "Cannot access KVM TLB\n");
1152 return;
1155 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1156 int size = booke206_tlb_size(env, i);
1158 if (size == 0) {
1159 continue;
1162 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1163 offset += size;
1167 static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
1168 CPUPPCState *env, int type)
1170 target_ulong *BATlt, *BATut, *BATu, *BATl;
1171 target_ulong BEPIl, BEPIu, bl;
1172 int i;
1174 switch (type) {
1175 case ACCESS_CODE:
1176 BATlt = env->IBAT[1];
1177 BATut = env->IBAT[0];
1178 break;
1179 default:
1180 BATlt = env->DBAT[1];
1181 BATut = env->DBAT[0];
1182 break;
1185 for (i = 0; i < env->nb_BATs; i++) {
1186 BATu = &BATut[i];
1187 BATl = &BATlt[i];
1188 BEPIu = *BATu & 0xF0000000;
1189 BEPIl = *BATu & 0x0FFE0000;
1190 bl = (*BATu & 0x00001FFC) << 15;
1191 cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx
1192 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
1193 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
1194 type == ACCESS_CODE ? "code" : "data", i,
1195 *BATu, *BATl, BEPIu, BEPIl, bl);
1199 static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1200 CPUPPCState *env)
1202 ppc6xx_tlb_t *tlb;
1203 target_ulong sr;
1204 int type, way, entry, i;
1206 cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
1207 cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
1209 cpu_fprintf(f, "\nSegment registers:\n");
1210 for (i = 0; i < 32; i++) {
1211 sr = env->sr[i];
1212 if (sr & 0x80000000) {
1213 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1214 "CNTLR_SPEC=0x%05x\n", i,
1215 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1216 sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
1217 (uint32_t)(sr & 0xFFFFF));
1218 } else {
1219 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
1220 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1221 sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
1222 (uint32_t)(sr & 0x00FFFFFF));
1226 cpu_fprintf(f, "\nBATs:\n");
1227 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT);
1228 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE);
1230 if (env->id_tlbs != 1) {
1231 cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB"
1232 " for code and data\n");
1235 cpu_fprintf(f, "\nTLBs [EPN EPN + SIZE]\n");
1237 for (type = 0; type < 2; type++) {
1238 for (way = 0; way < env->nb_ways; way++) {
1239 for (entry = env->nb_tlb * type + env->tlb_per_way * way;
1240 entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
1241 entry++) {
1243 tlb = &env->tlb.tlb6[entry];
1244 cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s ["
1245 TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
1246 type ? "code" : "data", entry % env->nb_tlb,
1247 env->nb_tlb, way,
1248 pte_is_valid(tlb->pte0) ? "valid" : "inval",
1249 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
1255 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1257 switch (env->mmu_model) {
1258 case POWERPC_MMU_BOOKE:
1259 mmubooke_dump_mmu(f, cpu_fprintf, env);
1260 break;
1261 case POWERPC_MMU_BOOKE206:
1262 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1263 break;
1264 case POWERPC_MMU_SOFT_6xx:
1265 case POWERPC_MMU_SOFT_74xx:
1266 mmu6xx_dump_mmu(f, cpu_fprintf, env);
1267 break;
1268 #if defined(TARGET_PPC64)
1269 case POWERPC_MMU_64B:
1270 case POWERPC_MMU_2_03:
1271 case POWERPC_MMU_2_06:
1272 case POWERPC_MMU_2_06a:
1273 case POWERPC_MMU_2_07:
1274 case POWERPC_MMU_2_07a:
1275 dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
1276 break;
1277 #endif
1278 default:
1279 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1283 static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1284 target_ulong eaddr, int rw)
1286 int in_plb, ret;
1288 ctx->raddr = eaddr;
1289 ctx->prot = PAGE_READ | PAGE_EXEC;
1290 ret = 0;
1291 switch (env->mmu_model) {
1292 case POWERPC_MMU_SOFT_6xx:
1293 case POWERPC_MMU_SOFT_74xx:
1294 case POWERPC_MMU_SOFT_4xx:
1295 case POWERPC_MMU_REAL:
1296 case POWERPC_MMU_BOOKE:
1297 ctx->prot |= PAGE_WRITE;
1298 break;
1300 case POWERPC_MMU_SOFT_4xx_Z:
1301 if (unlikely(msr_pe != 0)) {
1302 /* 403 family add some particular protections,
1303 * using PBL/PBU registers for accesses with no translation.
1305 in_plb =
1306 /* Check PLB validity */
1307 (env->pb[0] < env->pb[1] &&
1308 /* and address in plb area */
1309 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1310 (env->pb[2] < env->pb[3] &&
1311 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1312 if (in_plb ^ msr_px) {
1313 /* Access in protected area */
1314 if (rw == 1) {
1315 /* Access is not allowed */
1316 ret = -2;
1318 } else {
1319 /* Read-write access is allowed */
1320 ctx->prot |= PAGE_WRITE;
1323 break;
1325 default:
1326 /* Caller's checks mean we should never get here for other models */
1327 abort();
1328 return -1;
1331 return ret;
1334 static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1335 target_ulong eaddr, int rw, int access_type)
1337 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1338 int ret = -1;
1339 bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1340 || (access_type != ACCESS_CODE && msr_dr == 0);
1342 #if 0
1343 qemu_log("%s\n", __func__);
1344 #endif
1346 switch (env->mmu_model) {
1347 case POWERPC_MMU_SOFT_6xx:
1348 case POWERPC_MMU_SOFT_74xx:
1349 if (real_mode) {
1350 ret = check_physical(env, ctx, eaddr, rw);
1351 } else {
1352 /* Try to find a BAT */
1353 if (env->nb_BATs != 0) {
1354 ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
1356 if (ret < 0) {
1357 /* We didn't match any BAT entry or don't have BATs */
1358 ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1361 break;
1363 case POWERPC_MMU_SOFT_4xx:
1364 case POWERPC_MMU_SOFT_4xx_Z:
1365 if (real_mode) {
1366 ret = check_physical(env, ctx, eaddr, rw);
1367 } else {
1368 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1369 rw, access_type);
1371 break;
1372 case POWERPC_MMU_BOOKE:
1373 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1374 rw, access_type);
1375 break;
1376 case POWERPC_MMU_BOOKE206:
1377 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1378 access_type);
1379 break;
1380 case POWERPC_MMU_MPC8xx:
1381 /* XXX: TODO */
1382 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1383 break;
1384 case POWERPC_MMU_REAL:
1385 if (real_mode) {
1386 ret = check_physical(env, ctx, eaddr, rw);
1387 } else {
1388 cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n");
1390 return -1;
1391 default:
1392 cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
1393 return -1;
1395 #if 0
1396 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1397 __func__, eaddr, ret, ctx->raddr);
1398 #endif
1400 return ret;
1403 hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
1405 PowerPCCPU *cpu = POWERPC_CPU(cs);
1406 CPUPPCState *env = &cpu->env;
1407 mmu_ctx_t ctx;
1409 switch (env->mmu_model) {
1410 #if defined(TARGET_PPC64)
1411 case POWERPC_MMU_64B:
1412 case POWERPC_MMU_2_03:
1413 case POWERPC_MMU_2_06:
1414 case POWERPC_MMU_2_06a:
1415 case POWERPC_MMU_2_07:
1416 case POWERPC_MMU_2_07a:
1417 return ppc_hash64_get_phys_page_debug(cpu, addr);
1418 #endif
1420 case POWERPC_MMU_32B:
1421 case POWERPC_MMU_601:
1422 return ppc_hash32_get_phys_page_debug(cpu, addr);
1424 default:
1428 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1430 /* Some MMUs have separate TLBs for code and data. If we only try an
1431 * ACCESS_INT, we may not be able to read instructions mapped by code
1432 * TLBs, so we also try a ACCESS_CODE.
1434 if (unlikely(get_physical_address(env, &ctx, addr, 0,
1435 ACCESS_CODE) != 0)) {
1436 return -1;
1440 return ctx.raddr & TARGET_PAGE_MASK;
1443 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1444 int rw)
1446 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1447 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1448 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1449 env->spr[SPR_BOOKE_MAS3] = 0;
1450 env->spr[SPR_BOOKE_MAS6] = 0;
1451 env->spr[SPR_BOOKE_MAS7] = 0;
1453 /* AS */
1454 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1455 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1456 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1459 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1460 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1462 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1463 case MAS4_TIDSELD_PID0:
1464 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1465 break;
1466 case MAS4_TIDSELD_PID1:
1467 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1468 break;
1469 case MAS4_TIDSELD_PID2:
1470 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1471 break;
1474 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1476 /* next victim logic */
1477 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1478 env->last_way++;
1479 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1480 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1483 /* Perform address translation */
1484 static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
1485 int rw, int mmu_idx)
1487 CPUState *cs = CPU(ppc_env_get_cpu(env));
1488 PowerPCCPU *cpu = POWERPC_CPU(cs);
1489 mmu_ctx_t ctx;
1490 int access_type;
1491 int ret = 0;
1493 if (rw == 2) {
1494 /* code access */
1495 rw = 0;
1496 access_type = ACCESS_CODE;
1497 } else {
1498 /* data access */
1499 access_type = env->access_type;
1501 ret = get_physical_address(env, &ctx, address, rw, access_type);
1502 if (ret == 0) {
1503 tlb_set_page(cs, address & TARGET_PAGE_MASK,
1504 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1505 mmu_idx, TARGET_PAGE_SIZE);
1506 ret = 0;
1507 } else if (ret < 0) {
1508 LOG_MMU_STATE(cs);
1509 if (access_type == ACCESS_CODE) {
1510 switch (ret) {
1511 case -1:
1512 /* No matches in page tables or TLB */
1513 switch (env->mmu_model) {
1514 case POWERPC_MMU_SOFT_6xx:
1515 cs->exception_index = POWERPC_EXCP_IFTLB;
1516 env->error_code = 1 << 18;
1517 env->spr[SPR_IMISS] = address;
1518 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1519 goto tlb_miss;
1520 case POWERPC_MMU_SOFT_74xx:
1521 cs->exception_index = POWERPC_EXCP_IFTLB;
1522 goto tlb_miss_74xx;
1523 case POWERPC_MMU_SOFT_4xx:
1524 case POWERPC_MMU_SOFT_4xx_Z:
1525 cs->exception_index = POWERPC_EXCP_ITLB;
1526 env->error_code = 0;
1527 env->spr[SPR_40x_DEAR] = address;
1528 env->spr[SPR_40x_ESR] = 0x00000000;
1529 break;
1530 case POWERPC_MMU_BOOKE206:
1531 booke206_update_mas_tlb_miss(env, address, rw);
1532 /* fall through */
1533 case POWERPC_MMU_BOOKE:
1534 cs->exception_index = POWERPC_EXCP_ITLB;
1535 env->error_code = 0;
1536 env->spr[SPR_BOOKE_DEAR] = address;
1537 return -1;
1538 case POWERPC_MMU_MPC8xx:
1539 /* XXX: TODO */
1540 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1541 break;
1542 case POWERPC_MMU_REAL:
1543 cpu_abort(cs, "PowerPC in real mode should never raise "
1544 "any MMU exceptions\n");
1545 return -1;
1546 default:
1547 cpu_abort(cs, "Unknown or invalid MMU model\n");
1548 return -1;
1550 break;
1551 case -2:
1552 /* Access rights violation */
1553 cs->exception_index = POWERPC_EXCP_ISI;
1554 env->error_code = 0x08000000;
1555 break;
1556 case -3:
1557 /* No execute protection violation */
1558 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1559 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1560 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1562 cs->exception_index = POWERPC_EXCP_ISI;
1563 env->error_code = 0x10000000;
1564 break;
1565 case -4:
1566 /* Direct store exception */
1567 /* No code fetch is allowed in direct-store areas */
1568 cs->exception_index = POWERPC_EXCP_ISI;
1569 env->error_code = 0x10000000;
1570 break;
1572 } else {
1573 switch (ret) {
1574 case -1:
1575 /* No matches in page tables or TLB */
1576 switch (env->mmu_model) {
1577 case POWERPC_MMU_SOFT_6xx:
1578 if (rw == 1) {
1579 cs->exception_index = POWERPC_EXCP_DSTLB;
1580 env->error_code = 1 << 16;
1581 } else {
1582 cs->exception_index = POWERPC_EXCP_DLTLB;
1583 env->error_code = 0;
1585 env->spr[SPR_DMISS] = address;
1586 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1587 tlb_miss:
1588 env->error_code |= ctx.key << 19;
1589 env->spr[SPR_HASH1] = env->htab_base +
1590 get_pteg_offset32(cpu, ctx.hash[0]);
1591 env->spr[SPR_HASH2] = env->htab_base +
1592 get_pteg_offset32(cpu, ctx.hash[1]);
1593 break;
1594 case POWERPC_MMU_SOFT_74xx:
1595 if (rw == 1) {
1596 cs->exception_index = POWERPC_EXCP_DSTLB;
1597 } else {
1598 cs->exception_index = POWERPC_EXCP_DLTLB;
1600 tlb_miss_74xx:
1601 /* Implement LRU algorithm */
1602 env->error_code = ctx.key << 19;
1603 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1604 ((env->last_way + 1) & (env->nb_ways - 1));
1605 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1606 break;
1607 case POWERPC_MMU_SOFT_4xx:
1608 case POWERPC_MMU_SOFT_4xx_Z:
1609 cs->exception_index = POWERPC_EXCP_DTLB;
1610 env->error_code = 0;
1611 env->spr[SPR_40x_DEAR] = address;
1612 if (rw) {
1613 env->spr[SPR_40x_ESR] = 0x00800000;
1614 } else {
1615 env->spr[SPR_40x_ESR] = 0x00000000;
1617 break;
1618 case POWERPC_MMU_MPC8xx:
1619 /* XXX: TODO */
1620 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1621 break;
1622 case POWERPC_MMU_BOOKE206:
1623 booke206_update_mas_tlb_miss(env, address, rw);
1624 /* fall through */
1625 case POWERPC_MMU_BOOKE:
1626 cs->exception_index = POWERPC_EXCP_DTLB;
1627 env->error_code = 0;
1628 env->spr[SPR_BOOKE_DEAR] = address;
1629 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1630 return -1;
1631 case POWERPC_MMU_REAL:
1632 cpu_abort(cs, "PowerPC in real mode should never raise "
1633 "any MMU exceptions\n");
1634 return -1;
1635 default:
1636 cpu_abort(cs, "Unknown or invalid MMU model\n");
1637 return -1;
1639 break;
1640 case -2:
1641 /* Access rights violation */
1642 cs->exception_index = POWERPC_EXCP_DSI;
1643 env->error_code = 0;
1644 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1645 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1646 env->spr[SPR_40x_DEAR] = address;
1647 if (rw) {
1648 env->spr[SPR_40x_ESR] |= 0x00800000;
1650 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1651 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1652 env->spr[SPR_BOOKE_DEAR] = address;
1653 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1654 } else {
1655 env->spr[SPR_DAR] = address;
1656 if (rw == 1) {
1657 env->spr[SPR_DSISR] = 0x0A000000;
1658 } else {
1659 env->spr[SPR_DSISR] = 0x08000000;
1662 break;
1663 case -4:
1664 /* Direct store exception */
1665 switch (access_type) {
1666 case ACCESS_FLOAT:
1667 /* Floating point load/store */
1668 cs->exception_index = POWERPC_EXCP_ALIGN;
1669 env->error_code = POWERPC_EXCP_ALIGN_FP;
1670 env->spr[SPR_DAR] = address;
1671 break;
1672 case ACCESS_RES:
1673 /* lwarx, ldarx or stwcx. */
1674 cs->exception_index = POWERPC_EXCP_DSI;
1675 env->error_code = 0;
1676 env->spr[SPR_DAR] = address;
1677 if (rw == 1) {
1678 env->spr[SPR_DSISR] = 0x06000000;
1679 } else {
1680 env->spr[SPR_DSISR] = 0x04000000;
1682 break;
1683 case ACCESS_EXT:
1684 /* eciwx or ecowx */
1685 cs->exception_index = POWERPC_EXCP_DSI;
1686 env->error_code = 0;
1687 env->spr[SPR_DAR] = address;
1688 if (rw == 1) {
1689 env->spr[SPR_DSISR] = 0x06100000;
1690 } else {
1691 env->spr[SPR_DSISR] = 0x04100000;
1693 break;
1694 default:
1695 printf("DSI: invalid exception (%d)\n", ret);
1696 cs->exception_index = POWERPC_EXCP_PROGRAM;
1697 env->error_code =
1698 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1699 env->spr[SPR_DAR] = address;
1700 break;
1702 break;
1705 #if 0
1706 printf("%s: set exception to %d %02x\n", __func__,
1707 cs->exception, env->error_code);
1708 #endif
1709 ret = 1;
1712 return ret;
1715 /*****************************************************************************/
1716 /* BATs management */
1717 #if !defined(FLUSH_ALL_TLBS)
1718 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1719 target_ulong mask)
1721 CPUState *cs = CPU(ppc_env_get_cpu(env));
1722 target_ulong base, end, page;
1724 base = BATu & ~0x0001FFFF;
1725 end = base + mask + 0x00020000;
1726 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1727 TARGET_FMT_lx ")\n", base, end, mask);
1728 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
1729 tlb_flush_page(cs, page);
1731 LOG_BATS("Flush done\n");
1733 #endif
1735 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1736 target_ulong value)
1738 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1739 nr, ul == 0 ? 'u' : 'l', value, env->nip);
1742 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1744 target_ulong mask;
1746 dump_store_bat(env, 'I', 0, nr, value);
1747 if (env->IBAT[0][nr] != value) {
1748 mask = (value << 15) & 0x0FFE0000UL;
1749 #if !defined(FLUSH_ALL_TLBS)
1750 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1751 #endif
1752 /* When storing valid upper BAT, mask BEPI and BRPN
1753 * and invalidate all TLBs covered by this BAT
1755 mask = (value << 15) & 0x0FFE0000UL;
1756 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1757 (value & ~0x0001FFFFUL & ~mask);
1758 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1759 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1760 #if !defined(FLUSH_ALL_TLBS)
1761 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1762 #else
1763 tlb_flush(env, 1);
1764 #endif
1768 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1770 dump_store_bat(env, 'I', 1, nr, value);
1771 env->IBAT[1][nr] = value;
1774 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1776 target_ulong mask;
1778 dump_store_bat(env, 'D', 0, nr, value);
1779 if (env->DBAT[0][nr] != value) {
1780 /* When storing valid upper BAT, mask BEPI and BRPN
1781 * and invalidate all TLBs covered by this BAT
1783 mask = (value << 15) & 0x0FFE0000UL;
1784 #if !defined(FLUSH_ALL_TLBS)
1785 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1786 #endif
1787 mask = (value << 15) & 0x0FFE0000UL;
1788 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1789 (value & ~0x0001FFFFUL & ~mask);
1790 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1791 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1792 #if !defined(FLUSH_ALL_TLBS)
1793 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1794 #else
1795 tlb_flush(env, 1);
1796 #endif
1800 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1802 dump_store_bat(env, 'D', 1, nr, value);
1803 env->DBAT[1][nr] = value;
1806 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
1808 target_ulong mask;
1809 #if defined(FLUSH_ALL_TLBS)
1810 int do_inval;
1811 #endif
1813 dump_store_bat(env, 'I', 0, nr, value);
1814 if (env->IBAT[0][nr] != value) {
1815 #if defined(FLUSH_ALL_TLBS)
1816 do_inval = 0;
1817 #endif
1818 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1819 if (env->IBAT[1][nr] & 0x40) {
1820 /* Invalidate BAT only if it is valid */
1821 #if !defined(FLUSH_ALL_TLBS)
1822 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1823 #else
1824 do_inval = 1;
1825 #endif
1827 /* When storing valid upper BAT, mask BEPI and BRPN
1828 * and invalidate all TLBs covered by this BAT
1830 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1831 (value & ~0x0001FFFFUL & ~mask);
1832 env->DBAT[0][nr] = env->IBAT[0][nr];
1833 if (env->IBAT[1][nr] & 0x40) {
1834 #if !defined(FLUSH_ALL_TLBS)
1835 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1836 #else
1837 do_inval = 1;
1838 #endif
1840 #if defined(FLUSH_ALL_TLBS)
1841 if (do_inval) {
1842 tlb_flush(env, 1);
1844 #endif
1848 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
1850 #if !defined(FLUSH_ALL_TLBS)
1851 target_ulong mask;
1852 #else
1853 int do_inval;
1854 #endif
1856 dump_store_bat(env, 'I', 1, nr, value);
1857 if (env->IBAT[1][nr] != value) {
1858 #if defined(FLUSH_ALL_TLBS)
1859 do_inval = 0;
1860 #endif
1861 if (env->IBAT[1][nr] & 0x40) {
1862 #if !defined(FLUSH_ALL_TLBS)
1863 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1864 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1865 #else
1866 do_inval = 1;
1867 #endif
1869 if (value & 0x40) {
1870 #if !defined(FLUSH_ALL_TLBS)
1871 mask = (value << 17) & 0x0FFE0000UL;
1872 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1873 #else
1874 do_inval = 1;
1875 #endif
1877 env->IBAT[1][nr] = value;
1878 env->DBAT[1][nr] = value;
1879 #if defined(FLUSH_ALL_TLBS)
1880 if (do_inval) {
1881 tlb_flush(env, 1);
1883 #endif
1887 /*****************************************************************************/
1888 /* TLB management */
1889 void ppc_tlb_invalidate_all(CPUPPCState *env)
1891 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1893 switch (env->mmu_model) {
1894 case POWERPC_MMU_SOFT_6xx:
1895 case POWERPC_MMU_SOFT_74xx:
1896 ppc6xx_tlb_invalidate_all(env);
1897 break;
1898 case POWERPC_MMU_SOFT_4xx:
1899 case POWERPC_MMU_SOFT_4xx_Z:
1900 ppc4xx_tlb_invalidate_all(env);
1901 break;
1902 case POWERPC_MMU_REAL:
1903 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1904 break;
1905 case POWERPC_MMU_MPC8xx:
1906 /* XXX: TODO */
1907 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1908 break;
1909 case POWERPC_MMU_BOOKE:
1910 tlb_flush(CPU(cpu), 1);
1911 break;
1912 case POWERPC_MMU_BOOKE206:
1913 booke206_flush_tlb(env, -1, 0);
1914 break;
1915 case POWERPC_MMU_32B:
1916 case POWERPC_MMU_601:
1917 #if defined(TARGET_PPC64)
1918 case POWERPC_MMU_64B:
1919 case POWERPC_MMU_2_03:
1920 case POWERPC_MMU_2_06:
1921 case POWERPC_MMU_2_06a:
1922 case POWERPC_MMU_2_07:
1923 case POWERPC_MMU_2_07a:
1924 #endif /* defined(TARGET_PPC64) */
1925 tlb_flush(CPU(cpu), 1);
1926 break;
1927 default:
1928 /* XXX: TODO */
1929 cpu_abort(CPU(cpu), "Unknown MMU model\n");
1930 break;
1934 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
1936 #if !defined(FLUSH_ALL_TLBS)
1937 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1938 CPUState *cs;
1940 addr &= TARGET_PAGE_MASK;
1941 switch (env->mmu_model) {
1942 case POWERPC_MMU_SOFT_6xx:
1943 case POWERPC_MMU_SOFT_74xx:
1944 ppc6xx_tlb_invalidate_virt(env, addr, 0);
1945 if (env->id_tlbs == 1) {
1946 ppc6xx_tlb_invalidate_virt(env, addr, 1);
1948 break;
1949 case POWERPC_MMU_32B:
1950 case POWERPC_MMU_601:
1951 /* tlbie invalidate TLBs for all segments */
1952 addr &= ~((target_ulong)-1ULL << 28);
1953 cs = CPU(cpu);
1954 /* XXX: this case should be optimized,
1955 * giving a mask to tlb_flush_page
1957 tlb_flush_page(cs, addr | (0x0 << 28));
1958 tlb_flush_page(cs, addr | (0x1 << 28));
1959 tlb_flush_page(cs, addr | (0x2 << 28));
1960 tlb_flush_page(cs, addr | (0x3 << 28));
1961 tlb_flush_page(cs, addr | (0x4 << 28));
1962 tlb_flush_page(cs, addr | (0x5 << 28));
1963 tlb_flush_page(cs, addr | (0x6 << 28));
1964 tlb_flush_page(cs, addr | (0x7 << 28));
1965 tlb_flush_page(cs, addr | (0x8 << 28));
1966 tlb_flush_page(cs, addr | (0x9 << 28));
1967 tlb_flush_page(cs, addr | (0xA << 28));
1968 tlb_flush_page(cs, addr | (0xB << 28));
1969 tlb_flush_page(cs, addr | (0xC << 28));
1970 tlb_flush_page(cs, addr | (0xD << 28));
1971 tlb_flush_page(cs, addr | (0xE << 28));
1972 tlb_flush_page(cs, addr | (0xF << 28));
1973 break;
1974 #if defined(TARGET_PPC64)
1975 case POWERPC_MMU_64B:
1976 case POWERPC_MMU_2_03:
1977 case POWERPC_MMU_2_06:
1978 case POWERPC_MMU_2_06a:
1979 case POWERPC_MMU_2_07:
1980 case POWERPC_MMU_2_07a:
1981 /* tlbie invalidate TLBs for all segments */
1982 /* XXX: given the fact that there are too many segments to invalidate,
1983 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
1984 * we just invalidate all TLBs
1986 tlb_flush(CPU(cpu), 1);
1987 break;
1988 #endif /* defined(TARGET_PPC64) */
1989 default:
1990 /* Should never reach here with other MMU models */
1991 assert(0);
1993 #else
1994 ppc_tlb_invalidate_all(env);
1995 #endif
1998 /*****************************************************************************/
1999 /* Special registers manipulation */
2000 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2002 qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
2003 assert(!env->external_htab);
2004 env->spr[SPR_SDR1] = value;
2005 #if defined(TARGET_PPC64)
2006 if (env->mmu_model & POWERPC_MMU_64) {
2007 target_ulong htabsize = value & SDR_64_HTABSIZE;
2009 if (htabsize > 28) {
2010 fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
2011 " stored in SDR1\n", htabsize);
2012 htabsize = 28;
2014 env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
2015 env->htab_base = value & SDR_64_HTABORG;
2016 } else
2017 #endif /* defined(TARGET_PPC64) */
2019 /* FIXME: Should check for valid HTABMASK values */
2020 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2021 env->htab_base = value & SDR_32_HTABORG;
2025 /* Segment registers load and store */
2026 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2028 #if defined(TARGET_PPC64)
2029 if (env->mmu_model & POWERPC_MMU_64) {
2030 /* XXX */
2031 return 0;
2033 #endif
2034 return env->sr[sr_num];
2037 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2039 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2041 qemu_log_mask(CPU_LOG_MMU,
2042 "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2043 (int)srnum, value, env->sr[srnum]);
2044 #if defined(TARGET_PPC64)
2045 if (env->mmu_model & POWERPC_MMU_64) {
2046 uint64_t esid, vsid;
2048 /* ESID = srnum */
2049 esid = ((uint64_t)(srnum & 0xf) << 28) | SLB_ESID_V;
2051 /* VSID = VSID */
2052 vsid = (value & 0xfffffff) << 12;
2053 /* flags = flags */
2054 vsid |= ((value >> 27) & 0xf) << 8;
2056 ppc_store_slb(cpu, srnum, esid, vsid);
2057 } else
2058 #endif
2059 if (env->sr[srnum] != value) {
2060 env->sr[srnum] = value;
2061 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2062 flusing the whole TLB. */
2063 #if !defined(FLUSH_ALL_TLBS) && 0
2065 target_ulong page, end;
2066 /* Invalidate 256 MB of virtual memory */
2067 page = (16 << 20) * srnum;
2068 end = page + (16 << 20);
2069 for (; page != end; page += TARGET_PAGE_SIZE) {
2070 tlb_flush_page(CPU(cpu), page);
2073 #else
2074 tlb_flush(CPU(cpu), 1);
2075 #endif
2079 /* TLB management */
2080 void helper_tlbia(CPUPPCState *env)
2082 ppc_tlb_invalidate_all(env);
2085 void helper_tlbie(CPUPPCState *env, target_ulong addr)
2087 ppc_tlb_invalidate_one(env, addr);
2090 void helper_tlbiva(CPUPPCState *env, target_ulong addr)
2092 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2094 /* tlbiva instruction only exists on BookE */
2095 assert(env->mmu_model == POWERPC_MMU_BOOKE);
2096 /* XXX: TODO */
2097 cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
2100 /* Software driven TLBs management */
2101 /* PowerPC 602/603 software TLB load instructions helpers */
2102 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2104 target_ulong RPN, CMP, EPN;
2105 int way;
2107 RPN = env->spr[SPR_RPA];
2108 if (is_code) {
2109 CMP = env->spr[SPR_ICMP];
2110 EPN = env->spr[SPR_IMISS];
2111 } else {
2112 CMP = env->spr[SPR_DCMP];
2113 EPN = env->spr[SPR_DMISS];
2115 way = (env->spr[SPR_SRR1] >> 17) & 1;
2116 (void)EPN; /* avoid a compiler warning */
2117 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2118 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2119 RPN, way);
2120 /* Store this TLB */
2121 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2122 way, is_code, CMP, RPN);
2125 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2127 do_6xx_tlb(env, EPN, 0);
2130 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2132 do_6xx_tlb(env, EPN, 1);
2135 /* PowerPC 74xx software TLB load instructions helpers */
2136 static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2138 target_ulong RPN, CMP, EPN;
2139 int way;
2141 RPN = env->spr[SPR_PTELO];
2142 CMP = env->spr[SPR_PTEHI];
2143 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2144 way = env->spr[SPR_TLBMISS] & 0x3;
2145 (void)EPN; /* avoid a compiler warning */
2146 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2147 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2148 RPN, way);
2149 /* Store this TLB */
2150 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2151 way, is_code, CMP, RPN);
2154 void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2156 do_74xx_tlb(env, EPN, 0);
2159 void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2161 do_74xx_tlb(env, EPN, 1);
2164 /*****************************************************************************/
2165 /* PowerPC 601 specific instructions (POWER bridge) */
2167 target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2169 mmu_ctx_t ctx;
2170 int nb_BATs;
2171 target_ulong ret = 0;
2173 /* We don't have to generate many instances of this instruction,
2174 * as rac is supervisor only.
2176 /* XXX: FIX THIS: Pretend we have no BAT */
2177 nb_BATs = env->nb_BATs;
2178 env->nb_BATs = 0;
2179 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2180 ret = ctx.raddr;
2182 env->nb_BATs = nb_BATs;
2183 return ret;
2186 static inline target_ulong booke_tlb_to_page_size(int size)
2188 return 1024 << (2 * size);
2191 static inline int booke_page_size_to_tlb(target_ulong page_size)
2193 int size;
2195 switch (page_size) {
2196 case 0x00000400UL:
2197 size = 0x0;
2198 break;
2199 case 0x00001000UL:
2200 size = 0x1;
2201 break;
2202 case 0x00004000UL:
2203 size = 0x2;
2204 break;
2205 case 0x00010000UL:
2206 size = 0x3;
2207 break;
2208 case 0x00040000UL:
2209 size = 0x4;
2210 break;
2211 case 0x00100000UL:
2212 size = 0x5;
2213 break;
2214 case 0x00400000UL:
2215 size = 0x6;
2216 break;
2217 case 0x01000000UL:
2218 size = 0x7;
2219 break;
2220 case 0x04000000UL:
2221 size = 0x8;
2222 break;
2223 case 0x10000000UL:
2224 size = 0x9;
2225 break;
2226 case 0x40000000UL:
2227 size = 0xA;
2228 break;
2229 #if defined(TARGET_PPC64)
2230 case 0x000100000000ULL:
2231 size = 0xB;
2232 break;
2233 case 0x000400000000ULL:
2234 size = 0xC;
2235 break;
2236 case 0x001000000000ULL:
2237 size = 0xD;
2238 break;
2239 case 0x004000000000ULL:
2240 size = 0xE;
2241 break;
2242 case 0x010000000000ULL:
2243 size = 0xF;
2244 break;
2245 #endif
2246 default:
2247 size = -1;
2248 break;
2251 return size;
2254 /* Helpers for 4xx TLB management */
2255 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2257 #define PPC4XX_TLBHI_V 0x00000040
2258 #define PPC4XX_TLBHI_E 0x00000020
2259 #define PPC4XX_TLBHI_SIZE_MIN 0
2260 #define PPC4XX_TLBHI_SIZE_MAX 7
2261 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2262 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2263 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2265 #define PPC4XX_TLBLO_EX 0x00000200
2266 #define PPC4XX_TLBLO_WR 0x00000100
2267 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2268 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2270 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2272 ppcemb_tlb_t *tlb;
2273 target_ulong ret;
2274 int size;
2276 entry &= PPC4XX_TLB_ENTRY_MASK;
2277 tlb = &env->tlb.tlbe[entry];
2278 ret = tlb->EPN;
2279 if (tlb->prot & PAGE_VALID) {
2280 ret |= PPC4XX_TLBHI_V;
2282 size = booke_page_size_to_tlb(tlb->size);
2283 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2284 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2286 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2287 env->spr[SPR_40x_PID] = tlb->PID;
2288 return ret;
2291 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2293 ppcemb_tlb_t *tlb;
2294 target_ulong ret;
2296 entry &= PPC4XX_TLB_ENTRY_MASK;
2297 tlb = &env->tlb.tlbe[entry];
2298 ret = tlb->RPN;
2299 if (tlb->prot & PAGE_EXEC) {
2300 ret |= PPC4XX_TLBLO_EX;
2302 if (tlb->prot & PAGE_WRITE) {
2303 ret |= PPC4XX_TLBLO_WR;
2305 return ret;
2308 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2309 target_ulong val)
2311 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2312 CPUState *cs = CPU(cpu);
2313 ppcemb_tlb_t *tlb;
2314 target_ulong page, end;
2316 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2317 val);
2318 entry &= PPC4XX_TLB_ENTRY_MASK;
2319 tlb = &env->tlb.tlbe[entry];
2320 /* Invalidate previous TLB (if it's valid) */
2321 if (tlb->prot & PAGE_VALID) {
2322 end = tlb->EPN + tlb->size;
2323 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2324 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2325 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2326 tlb_flush_page(cs, page);
2329 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2330 & PPC4XX_TLBHI_SIZE_MASK);
2331 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2332 * If this ever occurs, one should use the ppcemb target instead
2333 * of the ppc or ppc64 one
2335 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2336 cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
2337 "are not supported (%d)\n",
2338 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2340 tlb->EPN = val & ~(tlb->size - 1);
2341 if (val & PPC4XX_TLBHI_V) {
2342 tlb->prot |= PAGE_VALID;
2343 if (val & PPC4XX_TLBHI_E) {
2344 /* XXX: TO BE FIXED */
2345 cpu_abort(cs,
2346 "Little-endian TLB entries are not supported by now\n");
2348 } else {
2349 tlb->prot &= ~PAGE_VALID;
2351 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2352 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2353 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2354 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2355 tlb->prot & PAGE_READ ? 'r' : '-',
2356 tlb->prot & PAGE_WRITE ? 'w' : '-',
2357 tlb->prot & PAGE_EXEC ? 'x' : '-',
2358 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2359 /* Invalidate new TLB (if valid) */
2360 if (tlb->prot & PAGE_VALID) {
2361 end = tlb->EPN + tlb->size;
2362 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2363 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2364 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2365 tlb_flush_page(cs, page);
2370 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2371 target_ulong val)
2373 ppcemb_tlb_t *tlb;
2375 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2376 val);
2377 entry &= PPC4XX_TLB_ENTRY_MASK;
2378 tlb = &env->tlb.tlbe[entry];
2379 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2380 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2381 tlb->prot = PAGE_READ;
2382 if (val & PPC4XX_TLBLO_EX) {
2383 tlb->prot |= PAGE_EXEC;
2385 if (val & PPC4XX_TLBLO_WR) {
2386 tlb->prot |= PAGE_WRITE;
2388 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2389 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2390 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2391 tlb->prot & PAGE_READ ? 'r' : '-',
2392 tlb->prot & PAGE_WRITE ? 'w' : '-',
2393 tlb->prot & PAGE_EXEC ? 'x' : '-',
2394 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2397 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2399 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2402 /* PowerPC 440 TLB management */
2403 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2404 target_ulong value)
2406 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2407 ppcemb_tlb_t *tlb;
2408 target_ulong EPN, RPN, size;
2409 int do_flush_tlbs;
2411 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2412 __func__, word, (int)entry, value);
2413 do_flush_tlbs = 0;
2414 entry &= 0x3F;
2415 tlb = &env->tlb.tlbe[entry];
2416 switch (word) {
2417 default:
2418 /* Just here to please gcc */
2419 case 0:
2420 EPN = value & 0xFFFFFC00;
2421 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2422 do_flush_tlbs = 1;
2424 tlb->EPN = EPN;
2425 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2426 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2427 do_flush_tlbs = 1;
2429 tlb->size = size;
2430 tlb->attr &= ~0x1;
2431 tlb->attr |= (value >> 8) & 1;
2432 if (value & 0x200) {
2433 tlb->prot |= PAGE_VALID;
2434 } else {
2435 if (tlb->prot & PAGE_VALID) {
2436 tlb->prot &= ~PAGE_VALID;
2437 do_flush_tlbs = 1;
2440 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2441 if (do_flush_tlbs) {
2442 tlb_flush(CPU(cpu), 1);
2444 break;
2445 case 1:
2446 RPN = value & 0xFFFFFC0F;
2447 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2448 tlb_flush(CPU(cpu), 1);
2450 tlb->RPN = RPN;
2451 break;
2452 case 2:
2453 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2454 tlb->prot = tlb->prot & PAGE_VALID;
2455 if (value & 0x1) {
2456 tlb->prot |= PAGE_READ << 4;
2458 if (value & 0x2) {
2459 tlb->prot |= PAGE_WRITE << 4;
2461 if (value & 0x4) {
2462 tlb->prot |= PAGE_EXEC << 4;
2464 if (value & 0x8) {
2465 tlb->prot |= PAGE_READ;
2467 if (value & 0x10) {
2468 tlb->prot |= PAGE_WRITE;
2470 if (value & 0x20) {
2471 tlb->prot |= PAGE_EXEC;
2473 break;
2477 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2478 target_ulong entry)
2480 ppcemb_tlb_t *tlb;
2481 target_ulong ret;
2482 int size;
2484 entry &= 0x3F;
2485 tlb = &env->tlb.tlbe[entry];
2486 switch (word) {
2487 default:
2488 /* Just here to please gcc */
2489 case 0:
2490 ret = tlb->EPN;
2491 size = booke_page_size_to_tlb(tlb->size);
2492 if (size < 0 || size > 0xF) {
2493 size = 1;
2495 ret |= size << 4;
2496 if (tlb->attr & 0x1) {
2497 ret |= 0x100;
2499 if (tlb->prot & PAGE_VALID) {
2500 ret |= 0x200;
2502 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2503 env->spr[SPR_440_MMUCR] |= tlb->PID;
2504 break;
2505 case 1:
2506 ret = tlb->RPN;
2507 break;
2508 case 2:
2509 ret = tlb->attr & ~0x1;
2510 if (tlb->prot & (PAGE_READ << 4)) {
2511 ret |= 0x1;
2513 if (tlb->prot & (PAGE_WRITE << 4)) {
2514 ret |= 0x2;
2516 if (tlb->prot & (PAGE_EXEC << 4)) {
2517 ret |= 0x4;
2519 if (tlb->prot & PAGE_READ) {
2520 ret |= 0x8;
2522 if (tlb->prot & PAGE_WRITE) {
2523 ret |= 0x10;
2525 if (tlb->prot & PAGE_EXEC) {
2526 ret |= 0x20;
2528 break;
2530 return ret;
2533 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2535 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2538 /* PowerPC BookE 2.06 TLB management */
2540 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2542 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2543 uint32_t tlbncfg = 0;
2544 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2545 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2546 int tlb;
2548 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2549 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2551 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2552 cpu_abort(CPU(cpu), "we don't support HES yet\n");
2555 return booke206_get_tlbm(env, tlb, ea, esel);
2558 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2560 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2562 env->spr[pidn] = pid;
2563 /* changing PIDs mean we're in a different address space now */
2564 tlb_flush(CPU(cpu), 1);
2567 void helper_booke206_tlbwe(CPUPPCState *env)
2569 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2570 uint32_t tlbncfg, tlbn;
2571 ppcmas_tlb_t *tlb;
2572 uint32_t size_tlb, size_ps;
2573 target_ulong mask;
2576 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2577 case MAS0_WQ_ALWAYS:
2578 /* good to go, write that entry */
2579 break;
2580 case MAS0_WQ_COND:
2581 /* XXX check if reserved */
2582 if (0) {
2583 return;
2585 break;
2586 case MAS0_WQ_CLR_RSRV:
2587 /* XXX clear entry */
2588 return;
2589 default:
2590 /* no idea what to do */
2591 return;
2594 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2595 !msr_gs) {
2596 /* XXX we don't support direct LRAT setting yet */
2597 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2598 return;
2601 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2602 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2604 tlb = booke206_cur_tlb(env);
2606 if (!tlb) {
2607 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2608 POWERPC_EXCP_INVAL |
2609 POWERPC_EXCP_INVAL_INVAL);
2612 /* check that we support the targeted size */
2613 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2614 size_ps = booke206_tlbnps(env, tlbn);
2615 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2616 !(size_ps & (1 << size_tlb))) {
2617 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2618 POWERPC_EXCP_INVAL |
2619 POWERPC_EXCP_INVAL_INVAL);
2622 if (msr_gs) {
2623 cpu_abort(CPU(cpu), "missing HV implementation\n");
2625 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2626 env->spr[SPR_BOOKE_MAS3];
2627 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2629 /* MAV 1.0 only */
2630 if (!(tlbncfg & TLBnCFG_AVAIL)) {
2631 /* force !AVAIL TLB entries to correct page size */
2632 tlb->mas1 &= ~MAS1_TSIZE_MASK;
2633 /* XXX can be configured in MMUCSR0 */
2634 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2637 /* Make a mask from TLB size to discard invalid bits in EPN field */
2638 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2639 /* Add a mask for page attributes */
2640 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2642 if (!msr_cm) {
2643 /* Executing a tlbwe instruction in 32-bit mode will set
2644 * bits 0:31 of the TLB EPN field to zero.
2646 mask &= 0xffffffff;
2649 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
2651 if (!(tlbncfg & TLBnCFG_IPROT)) {
2652 /* no IPROT supported by TLB */
2653 tlb->mas1 &= ~MAS1_IPROT;
2656 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
2657 tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
2658 } else {
2659 tlb_flush(CPU(cpu), 1);
2663 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2665 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2666 int way = booke206_tlbm_to_way(env, tlb);
2668 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2669 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2670 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2672 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2673 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2674 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2675 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2678 void helper_booke206_tlbre(CPUPPCState *env)
2680 ppcmas_tlb_t *tlb = NULL;
2682 tlb = booke206_cur_tlb(env);
2683 if (!tlb) {
2684 env->spr[SPR_BOOKE_MAS1] = 0;
2685 } else {
2686 booke206_tlb_to_mas(env, tlb);
2690 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
2692 ppcmas_tlb_t *tlb = NULL;
2693 int i, j;
2694 hwaddr raddr;
2695 uint32_t spid, sas;
2697 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2698 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2700 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2701 int ways = booke206_tlb_ways(env, i);
2703 for (j = 0; j < ways; j++) {
2704 tlb = booke206_get_tlbm(env, i, address, j);
2706 if (!tlb) {
2707 continue;
2710 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2711 continue;
2714 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2715 continue;
2718 booke206_tlb_to_mas(env, tlb);
2719 return;
2723 /* no entry found, fill with defaults */
2724 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2725 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2726 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2727 env->spr[SPR_BOOKE_MAS3] = 0;
2728 env->spr[SPR_BOOKE_MAS7] = 0;
2730 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2731 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2734 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2735 << MAS1_TID_SHIFT;
2737 /* next victim logic */
2738 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2739 env->last_way++;
2740 env->last_way &= booke206_tlb_ways(env, 0) - 1;
2741 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2744 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2745 uint32_t ea)
2747 int i;
2748 int ways = booke206_tlb_ways(env, tlbn);
2749 target_ulong mask;
2751 for (i = 0; i < ways; i++) {
2752 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2753 if (!tlb) {
2754 continue;
2756 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2757 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2758 !(tlb->mas1 & MAS1_IPROT)) {
2759 tlb->mas1 &= ~MAS1_VALID;
2764 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
2766 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2768 if (address & 0x4) {
2769 /* flush all entries */
2770 if (address & 0x8) {
2771 /* flush all of TLB1 */
2772 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2773 } else {
2774 /* flush all of TLB0 */
2775 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2777 return;
2780 if (address & 0x8) {
2781 /* flush TLB1 entries */
2782 booke206_invalidate_ea_tlb(env, 1, address);
2783 tlb_flush(CPU(cpu), 1);
2784 } else {
2785 /* flush TLB0 entries */
2786 booke206_invalidate_ea_tlb(env, 0, address);
2787 tlb_flush_page(CPU(cpu), address & MAS2_EPN_MASK);
2791 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
2793 /* XXX missing LPID handling */
2794 booke206_flush_tlb(env, -1, 1);
2797 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
2799 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2800 int i, j;
2801 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2802 ppcmas_tlb_t *tlb = env->tlb.tlbm;
2803 int tlb_size;
2805 /* XXX missing LPID handling */
2806 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2807 tlb_size = booke206_tlb_size(env, i);
2808 for (j = 0; j < tlb_size; j++) {
2809 if (!(tlb[j].mas1 & MAS1_IPROT) &&
2810 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2811 tlb[j].mas1 &= ~MAS1_VALID;
2814 tlb += booke206_tlb_size(env, i);
2816 tlb_flush(CPU(cpu), 1);
2819 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
2821 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2822 int i, j;
2823 ppcmas_tlb_t *tlb;
2824 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2825 int pid = tid >> MAS6_SPID_SHIFT;
2826 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2827 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
2828 /* XXX check for unsupported isize and raise an invalid opcode then */
2829 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
2830 /* XXX implement MAV2 handling */
2831 bool mav2 = false;
2833 /* XXX missing LPID handling */
2834 /* flush by pid and ea */
2835 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2836 int ways = booke206_tlb_ways(env, i);
2838 for (j = 0; j < ways; j++) {
2839 tlb = booke206_get_tlbm(env, i, address, j);
2840 if (!tlb) {
2841 continue;
2843 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
2844 (tlb->mas1 & MAS1_IPROT) ||
2845 ((tlb->mas1 & MAS1_IND) != ind) ||
2846 ((tlb->mas8 & MAS8_TGS) != sgs)) {
2847 continue;
2849 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
2850 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2851 continue;
2853 /* XXX e500mc doesn't match SAS, but other cores might */
2854 tlb->mas1 &= ~MAS1_VALID;
2857 tlb_flush(CPU(cpu), 1);
2860 void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
2862 int flags = 0;
2864 if (type & 2) {
2865 flags |= BOOKE206_FLUSH_TLB1;
2868 if (type & 4) {
2869 flags |= BOOKE206_FLUSH_TLB0;
2872 booke206_flush_tlb(env, flags, 1);
2876 /*****************************************************************************/
2878 /* try to fill the TLB and return an exception if error. If retaddr is
2879 NULL, it means that the function was called in C code (i.e. not
2880 from generated code or from helper.c) */
2881 /* XXX: fix it to restore all registers */
2882 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
2883 uintptr_t retaddr)
2885 PowerPCCPU *cpu = POWERPC_CPU(cs);
2886 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
2887 CPUPPCState *env = &cpu->env;
2888 int ret;
2890 if (pcc->handle_mmu_fault) {
2891 ret = pcc->handle_mmu_fault(cpu, addr, is_write, mmu_idx);
2892 } else {
2893 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
2895 if (unlikely(ret != 0)) {
2896 if (likely(retaddr)) {
2897 /* now we have a real cpu fault */
2898 cpu_restore_state(cs, retaddr);
2900 helper_raise_exception_err(env, cs->exception_index, env->error_code);