esp: check dma length before reading scsi command(CVE-2016-4441)
[qemu/ar7.git] / target-ppc / mmu_helper.c
blob2e0e3ca92cf88b64a73ae03650bb29670afddf07
1 /*
2 * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
4 * Copyright (c) 2003-2007 Jocelyn Mayer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #include "qemu/osdep.h"
20 #include "qapi/error.h"
21 #include "cpu.h"
22 #include "exec/helper-proto.h"
23 #include "sysemu/kvm.h"
24 #include "kvm_ppc.h"
25 #include "mmu-hash64.h"
26 #include "mmu-hash32.h"
27 #include "exec/exec-all.h"
28 #include "exec/cpu_ldst.h"
29 #include "exec/log.h"
31 //#define DEBUG_MMU
32 //#define DEBUG_BATS
33 //#define DEBUG_SOFTWARE_TLB
34 //#define DUMP_PAGE_TABLES
35 //#define FLUSH_ALL_TLBS
37 #ifdef DEBUG_MMU
38 # define LOG_MMU_STATE(cpu) log_cpu_state_mask(CPU_LOG_MMU, (cpu), 0)
39 #else
40 # define LOG_MMU_STATE(cpu) do { } while (0)
41 #endif
43 #ifdef DEBUG_SOFTWARE_TLB
44 # define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
45 #else
46 # define LOG_SWTLB(...) do { } while (0)
47 #endif
49 #ifdef DEBUG_BATS
50 # define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
51 #else
52 # define LOG_BATS(...) do { } while (0)
53 #endif
55 /*****************************************************************************/
56 /* PowerPC MMU emulation */
58 /* Context used internally during MMU translations */
59 typedef struct mmu_ctx_t mmu_ctx_t;
60 struct mmu_ctx_t {
61 hwaddr raddr; /* Real address */
62 hwaddr eaddr; /* Effective address */
63 int prot; /* Protection bits */
64 hwaddr hash[2]; /* Pagetable hash values */
65 target_ulong ptem; /* Virtual segment ID | API */
66 int key; /* Access key */
67 int nx; /* Non-execute area */
70 /* Common routines used by software and hardware TLBs emulation */
71 static inline int pte_is_valid(target_ulong pte0)
73 return pte0 & 0x80000000 ? 1 : 0;
76 static inline void pte_invalidate(target_ulong *pte0)
78 *pte0 &= ~0x80000000;
81 #define PTE_PTEM_MASK 0x7FFFFFBF
82 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
84 static int pp_check(int key, int pp, int nx)
86 int access;
88 /* Compute access rights */
89 access = 0;
90 if (key == 0) {
91 switch (pp) {
92 case 0x0:
93 case 0x1:
94 case 0x2:
95 access |= PAGE_WRITE;
96 /* No break here */
97 case 0x3:
98 access |= PAGE_READ;
99 break;
101 } else {
102 switch (pp) {
103 case 0x0:
104 access = 0;
105 break;
106 case 0x1:
107 case 0x3:
108 access = PAGE_READ;
109 break;
110 case 0x2:
111 access = PAGE_READ | PAGE_WRITE;
112 break;
115 if (nx == 0) {
116 access |= PAGE_EXEC;
119 return access;
122 static int check_prot(int prot, int rw, int access_type)
124 int ret;
126 if (access_type == ACCESS_CODE) {
127 if (prot & PAGE_EXEC) {
128 ret = 0;
129 } else {
130 ret = -2;
132 } else if (rw) {
133 if (prot & PAGE_WRITE) {
134 ret = 0;
135 } else {
136 ret = -2;
138 } else {
139 if (prot & PAGE_READ) {
140 ret = 0;
141 } else {
142 ret = -2;
146 return ret;
149 static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
150 target_ulong pte1, int h, int rw, int type)
152 target_ulong ptem, mmask;
153 int access, ret, pteh, ptev, pp;
155 ret = -1;
156 /* Check validity and table match */
157 ptev = pte_is_valid(pte0);
158 pteh = (pte0 >> 6) & 1;
159 if (ptev && h == pteh) {
160 /* Check vsid & api */
161 ptem = pte0 & PTE_PTEM_MASK;
162 mmask = PTE_CHECK_MASK;
163 pp = pte1 & 0x00000003;
164 if (ptem == ctx->ptem) {
165 if (ctx->raddr != (hwaddr)-1ULL) {
166 /* all matches should have equal RPN, WIMG & PP */
167 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
168 qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
169 return -3;
172 /* Compute access rights */
173 access = pp_check(ctx->key, pp, ctx->nx);
174 /* Keep the matching PTE informations */
175 ctx->raddr = pte1;
176 ctx->prot = access;
177 ret = check_prot(ctx->prot, rw, type);
178 if (ret == 0) {
179 /* Access granted */
180 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
181 } else {
182 /* Access right violation */
183 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
188 return ret;
191 static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
192 int ret, int rw)
194 int store = 0;
196 /* Update page flags */
197 if (!(*pte1p & 0x00000100)) {
198 /* Update accessed flag */
199 *pte1p |= 0x00000100;
200 store = 1;
202 if (!(*pte1p & 0x00000080)) {
203 if (rw == 1 && ret == 0) {
204 /* Update changed flag */
205 *pte1p |= 0x00000080;
206 store = 1;
207 } else {
208 /* Force page fault for first write access */
209 ctx->prot &= ~PAGE_WRITE;
213 return store;
216 /* Software driven TLB helpers */
217 static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
218 int way, int is_code)
220 int nr;
222 /* Select TLB num in a way from address */
223 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
224 /* Select TLB way */
225 nr += env->tlb_per_way * way;
226 /* 6xx have separate TLBs for instructions and data */
227 if (is_code && env->id_tlbs == 1) {
228 nr += env->nb_tlb;
231 return nr;
234 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
236 PowerPCCPU *cpu = ppc_env_get_cpu(env);
237 ppc6xx_tlb_t *tlb;
238 int nr, max;
240 /* LOG_SWTLB("Invalidate all TLBs\n"); */
241 /* Invalidate all defined software TLB */
242 max = env->nb_tlb;
243 if (env->id_tlbs == 1) {
244 max *= 2;
246 for (nr = 0; nr < max; nr++) {
247 tlb = &env->tlb.tlb6[nr];
248 pte_invalidate(&tlb->pte0);
250 tlb_flush(CPU(cpu), 1);
253 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
254 target_ulong eaddr,
255 int is_code, int match_epn)
257 #if !defined(FLUSH_ALL_TLBS)
258 CPUState *cs = CPU(ppc_env_get_cpu(env));
259 ppc6xx_tlb_t *tlb;
260 int way, nr;
262 /* Invalidate ITLB + DTLB, all ways */
263 for (way = 0; way < env->nb_ways; way++) {
264 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
265 tlb = &env->tlb.tlb6[nr];
266 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
267 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
268 env->nb_tlb, eaddr);
269 pte_invalidate(&tlb->pte0);
270 tlb_flush_page(cs, tlb->EPN);
273 #else
274 /* XXX: PowerPC specification say this is valid as well */
275 ppc6xx_tlb_invalidate_all(env);
276 #endif
279 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
280 target_ulong eaddr, int is_code)
282 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
285 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
286 int is_code, target_ulong pte0, target_ulong pte1)
288 ppc6xx_tlb_t *tlb;
289 int nr;
291 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
292 tlb = &env->tlb.tlb6[nr];
293 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
294 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
295 /* Invalidate any pending reference in QEMU for this virtual address */
296 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
297 tlb->pte0 = pte0;
298 tlb->pte1 = pte1;
299 tlb->EPN = EPN;
300 /* Store last way for LRU mechanism */
301 env->last_way = way;
304 static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
305 target_ulong eaddr, int rw, int access_type)
307 ppc6xx_tlb_t *tlb;
308 int nr, best, way;
309 int ret;
311 best = -1;
312 ret = -1; /* No TLB found */
313 for (way = 0; way < env->nb_ways; way++) {
314 nr = ppc6xx_tlb_getnum(env, eaddr, way,
315 access_type == ACCESS_CODE ? 1 : 0);
316 tlb = &env->tlb.tlb6[nr];
317 /* This test "emulates" the PTE index match for hardware TLBs */
318 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
319 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
320 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
321 pte_is_valid(tlb->pte0) ? "valid" : "inval",
322 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
323 continue;
325 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
326 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
327 pte_is_valid(tlb->pte0) ? "valid" : "inval",
328 tlb->EPN, eaddr, tlb->pte1,
329 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
330 switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
331 case -3:
332 /* TLB inconsistency */
333 return -1;
334 case -2:
335 /* Access violation */
336 ret = -2;
337 best = nr;
338 break;
339 case -1:
340 default:
341 /* No match */
342 break;
343 case 0:
344 /* access granted */
345 /* XXX: we should go on looping to check all TLBs consistency
346 * but we can speed-up the whole thing as the
347 * result would be undefined if TLBs are not consistent.
349 ret = 0;
350 best = nr;
351 goto done;
354 if (best != -1) {
355 done:
356 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
357 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
358 /* Update page flags */
359 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
362 return ret;
365 /* Perform BAT hit & translation */
366 static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
367 int *validp, int *protp, target_ulong *BATu,
368 target_ulong *BATl)
370 target_ulong bl;
371 int pp, valid, prot;
373 bl = (*BATu & 0x00001FFC) << 15;
374 valid = 0;
375 prot = 0;
376 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
377 ((msr_pr != 0) && (*BATu & 0x00000001))) {
378 valid = 1;
379 pp = *BATl & 0x00000003;
380 if (pp != 0) {
381 prot = PAGE_READ | PAGE_EXEC;
382 if (pp == 0x2) {
383 prot |= PAGE_WRITE;
387 *blp = bl;
388 *validp = valid;
389 *protp = prot;
392 static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
393 target_ulong virtual, int rw, int type)
395 target_ulong *BATlt, *BATut, *BATu, *BATl;
396 target_ulong BEPIl, BEPIu, bl;
397 int i, valid, prot;
398 int ret = -1;
400 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
401 type == ACCESS_CODE ? 'I' : 'D', virtual);
402 switch (type) {
403 case ACCESS_CODE:
404 BATlt = env->IBAT[1];
405 BATut = env->IBAT[0];
406 break;
407 default:
408 BATlt = env->DBAT[1];
409 BATut = env->DBAT[0];
410 break;
412 for (i = 0; i < env->nb_BATs; i++) {
413 BATu = &BATut[i];
414 BATl = &BATlt[i];
415 BEPIu = *BATu & 0xF0000000;
416 BEPIl = *BATu & 0x0FFE0000;
417 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
418 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
419 " BATl " TARGET_FMT_lx "\n", __func__,
420 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
421 if ((virtual & 0xF0000000) == BEPIu &&
422 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
423 /* BAT matches */
424 if (valid != 0) {
425 /* Get physical address */
426 ctx->raddr = (*BATl & 0xF0000000) |
427 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
428 (virtual & 0x0001F000);
429 /* Compute access rights */
430 ctx->prot = prot;
431 ret = check_prot(ctx->prot, rw, type);
432 if (ret == 0) {
433 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
434 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
435 ctx->prot & PAGE_WRITE ? 'W' : '-');
437 break;
441 if (ret < 0) {
442 #if defined(DEBUG_BATS)
443 if (qemu_log_enabled()) {
444 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
445 for (i = 0; i < 4; i++) {
446 BATu = &BATut[i];
447 BATl = &BATlt[i];
448 BEPIu = *BATu & 0xF0000000;
449 BEPIl = *BATu & 0x0FFE0000;
450 bl = (*BATu & 0x00001FFC) << 15;
451 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
452 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
453 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
454 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
455 *BATu, *BATl, BEPIu, BEPIl, bl);
458 #endif
460 /* No hit */
461 return ret;
464 /* Perform segment based translation */
465 static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
466 target_ulong eaddr, int rw, int type)
468 hwaddr hash;
469 target_ulong vsid;
470 int ds, pr, target_page_bits;
471 int ret;
472 target_ulong sr, pgidx;
474 pr = msr_pr;
475 ctx->eaddr = eaddr;
477 sr = env->sr[eaddr >> 28];
478 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
479 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
480 ds = sr & 0x80000000 ? 1 : 0;
481 ctx->nx = sr & 0x10000000 ? 1 : 0;
482 vsid = sr & 0x00FFFFFF;
483 target_page_bits = TARGET_PAGE_BITS;
484 qemu_log_mask(CPU_LOG_MMU,
485 "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
486 " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
487 " ir=%d dr=%d pr=%d %d t=%d\n",
488 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
489 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
490 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
491 hash = vsid ^ pgidx;
492 ctx->ptem = (vsid << 7) | (pgidx >> 10);
494 qemu_log_mask(CPU_LOG_MMU,
495 "pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
496 ctx->key, ds, ctx->nx, vsid);
497 ret = -1;
498 if (!ds) {
499 /* Check if instruction fetch is allowed, if needed */
500 if (type != ACCESS_CODE || ctx->nx == 0) {
501 /* Page address translation */
502 qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
503 " htab_mask " TARGET_FMT_plx
504 " hash " TARGET_FMT_plx "\n",
505 env->htab_base, env->htab_mask, hash);
506 ctx->hash[0] = hash;
507 ctx->hash[1] = ~hash;
509 /* Initialize real address with an invalid value */
510 ctx->raddr = (hwaddr)-1ULL;
511 /* Software TLB search */
512 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
513 #if defined(DUMP_PAGE_TABLES)
514 if (qemu_log_mask(CPU_LOG_MMU)) {
515 hwaddr curaddr;
516 uint32_t a0, a1, a2, a3;
518 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
519 "\n", sdr, mask + 0x80);
520 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
521 curaddr += 16) {
522 a0 = ldl_phys(curaddr);
523 a1 = ldl_phys(curaddr + 4);
524 a2 = ldl_phys(curaddr + 8);
525 a3 = ldl_phys(curaddr + 12);
526 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
527 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
528 curaddr, a0, a1, a2, a3);
532 #endif
533 } else {
534 qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
535 ret = -3;
537 } else {
538 target_ulong sr;
540 qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
541 /* Direct-store segment : absolutely *BUGGY* for now */
543 /* Direct-store implies a 32-bit MMU.
544 * Check the Segment Register's bus unit ID (BUID).
546 sr = env->sr[eaddr >> 28];
547 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
548 /* Memory-forced I/O controller interface access */
549 /* If T=1 and BUID=x'07F', the 601 performs a memory access
550 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
552 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
553 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
554 return 0;
557 switch (type) {
558 case ACCESS_INT:
559 /* Integer load/store : only access allowed */
560 break;
561 case ACCESS_CODE:
562 /* No code fetch is allowed in direct-store areas */
563 return -4;
564 case ACCESS_FLOAT:
565 /* Floating point load/store */
566 return -4;
567 case ACCESS_RES:
568 /* lwarx, ldarx or srwcx. */
569 return -4;
570 case ACCESS_CACHE:
571 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
572 /* Should make the instruction do no-op.
573 * As it already do no-op, it's quite easy :-)
575 ctx->raddr = eaddr;
576 return 0;
577 case ACCESS_EXT:
578 /* eciwx or ecowx */
579 return -4;
580 default:
581 qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need "
582 "address translation\n");
583 return -4;
585 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
586 ctx->raddr = eaddr;
587 ret = 2;
588 } else {
589 ret = -2;
593 return ret;
596 /* Generic TLB check function for embedded PowerPC implementations */
597 static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
598 hwaddr *raddrp,
599 target_ulong address, uint32_t pid, int ext,
600 int i)
602 target_ulong mask;
604 /* Check valid flag */
605 if (!(tlb->prot & PAGE_VALID)) {
606 return -1;
608 mask = ~(tlb->size - 1);
609 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
610 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
611 mask, (uint32_t)tlb->PID, tlb->prot);
612 /* Check PID */
613 if (tlb->PID != 0 && tlb->PID != pid) {
614 return -1;
616 /* Check effective address */
617 if ((address & mask) != tlb->EPN) {
618 return -1;
620 *raddrp = (tlb->RPN & mask) | (address & ~mask);
621 if (ext) {
622 /* Extend the physical address to 36 bits */
623 *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
626 return 0;
629 /* Generic TLB search function for PowerPC embedded implementations */
630 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
631 uint32_t pid)
633 ppcemb_tlb_t *tlb;
634 hwaddr raddr;
635 int i, ret;
637 /* Default return value is no match */
638 ret = -1;
639 for (i = 0; i < env->nb_tlb; i++) {
640 tlb = &env->tlb.tlbe[i];
641 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
642 ret = i;
643 break;
647 return ret;
650 /* Helpers specific to PowerPC 40x implementations */
651 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
653 PowerPCCPU *cpu = ppc_env_get_cpu(env);
654 ppcemb_tlb_t *tlb;
655 int i;
657 for (i = 0; i < env->nb_tlb; i++) {
658 tlb = &env->tlb.tlbe[i];
659 tlb->prot &= ~PAGE_VALID;
661 tlb_flush(CPU(cpu), 1);
664 static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
665 target_ulong address, int rw,
666 int access_type)
668 ppcemb_tlb_t *tlb;
669 hwaddr raddr;
670 int i, ret, zsel, zpr, pr;
672 ret = -1;
673 raddr = (hwaddr)-1ULL;
674 pr = msr_pr;
675 for (i = 0; i < env->nb_tlb; i++) {
676 tlb = &env->tlb.tlbe[i];
677 if (ppcemb_tlb_check(env, tlb, &raddr, address,
678 env->spr[SPR_40x_PID], 0, i) < 0) {
679 continue;
681 zsel = (tlb->attr >> 4) & 0xF;
682 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
683 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
684 __func__, i, zsel, zpr, rw, tlb->attr);
685 /* Check execute enable bit */
686 switch (zpr) {
687 case 0x2:
688 if (pr != 0) {
689 goto check_perms;
691 /* No break here */
692 case 0x3:
693 /* All accesses granted */
694 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
695 ret = 0;
696 break;
697 case 0x0:
698 if (pr != 0) {
699 /* Raise Zone protection fault. */
700 env->spr[SPR_40x_ESR] = 1 << 22;
701 ctx->prot = 0;
702 ret = -2;
703 break;
705 /* No break here */
706 case 0x1:
707 check_perms:
708 /* Check from TLB entry */
709 ctx->prot = tlb->prot;
710 ret = check_prot(ctx->prot, rw, access_type);
711 if (ret == -2) {
712 env->spr[SPR_40x_ESR] = 0;
714 break;
716 if (ret >= 0) {
717 ctx->raddr = raddr;
718 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
719 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
720 ret);
721 return 0;
724 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
725 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
727 return ret;
730 void store_40x_sler(CPUPPCState *env, uint32_t val)
732 PowerPCCPU *cpu = ppc_env_get_cpu(env);
734 /* XXX: TO BE FIXED */
735 if (val != 0x00000000) {
736 cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
738 env->spr[SPR_405_SLER] = val;
741 static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
742 hwaddr *raddr, int *prot,
743 target_ulong address, int rw,
744 int access_type, int i)
746 int ret, prot2;
748 if (ppcemb_tlb_check(env, tlb, raddr, address,
749 env->spr[SPR_BOOKE_PID],
750 !env->nb_pids, i) >= 0) {
751 goto found_tlb;
754 if (env->spr[SPR_BOOKE_PID1] &&
755 ppcemb_tlb_check(env, tlb, raddr, address,
756 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
757 goto found_tlb;
760 if (env->spr[SPR_BOOKE_PID2] &&
761 ppcemb_tlb_check(env, tlb, raddr, address,
762 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
763 goto found_tlb;
766 LOG_SWTLB("%s: TLB entry not found\n", __func__);
767 return -1;
769 found_tlb:
771 if (msr_pr != 0) {
772 prot2 = tlb->prot & 0xF;
773 } else {
774 prot2 = (tlb->prot >> 4) & 0xF;
777 /* Check the address space */
778 if (access_type == ACCESS_CODE) {
779 if (msr_ir != (tlb->attr & 1)) {
780 LOG_SWTLB("%s: AS doesn't match\n", __func__);
781 return -1;
784 *prot = prot2;
785 if (prot2 & PAGE_EXEC) {
786 LOG_SWTLB("%s: good TLB!\n", __func__);
787 return 0;
790 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
791 ret = -3;
792 } else {
793 if (msr_dr != (tlb->attr & 1)) {
794 LOG_SWTLB("%s: AS doesn't match\n", __func__);
795 return -1;
798 *prot = prot2;
799 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
800 LOG_SWTLB("%s: found TLB!\n", __func__);
801 return 0;
804 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
805 ret = -2;
808 return ret;
811 static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
812 target_ulong address, int rw,
813 int access_type)
815 ppcemb_tlb_t *tlb;
816 hwaddr raddr;
817 int i, ret;
819 ret = -1;
820 raddr = (hwaddr)-1ULL;
821 for (i = 0; i < env->nb_tlb; i++) {
822 tlb = &env->tlb.tlbe[i];
823 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
824 access_type, i);
825 if (!ret) {
826 break;
830 if (ret >= 0) {
831 ctx->raddr = raddr;
832 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
833 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
834 ret);
835 } else {
836 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
837 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
840 return ret;
843 static void booke206_flush_tlb(CPUPPCState *env, int flags,
844 const int check_iprot)
846 PowerPCCPU *cpu = ppc_env_get_cpu(env);
847 int tlb_size;
848 int i, j;
849 ppcmas_tlb_t *tlb = env->tlb.tlbm;
851 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
852 if (flags & (1 << i)) {
853 tlb_size = booke206_tlb_size(env, i);
854 for (j = 0; j < tlb_size; j++) {
855 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
856 tlb[j].mas1 &= ~MAS1_VALID;
860 tlb += booke206_tlb_size(env, i);
863 tlb_flush(CPU(cpu), 1);
866 static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
867 ppcmas_tlb_t *tlb)
869 int tlbm_size;
871 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
873 return 1024ULL << tlbm_size;
876 /* TLB check function for MAS based SoftTLBs */
877 static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
878 hwaddr *raddrp, target_ulong address,
879 uint32_t pid)
881 hwaddr mask;
882 uint32_t tlb_pid;
884 if (!msr_cm) {
885 /* In 32bit mode we can only address 32bit EAs */
886 address = (uint32_t)address;
889 /* Check valid flag */
890 if (!(tlb->mas1 & MAS1_VALID)) {
891 return -1;
894 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
895 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
896 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
897 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
898 tlb->mas8);
900 /* Check PID */
901 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
902 if (tlb_pid != 0 && tlb_pid != pid) {
903 return -1;
906 /* Check effective address */
907 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
908 return -1;
911 if (raddrp) {
912 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
915 return 0;
918 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
919 hwaddr *raddr, int *prot,
920 target_ulong address, int rw,
921 int access_type)
923 int ret;
924 int prot2 = 0;
926 if (ppcmas_tlb_check(env, tlb, raddr, address,
927 env->spr[SPR_BOOKE_PID]) >= 0) {
928 goto found_tlb;
931 if (env->spr[SPR_BOOKE_PID1] &&
932 ppcmas_tlb_check(env, tlb, raddr, address,
933 env->spr[SPR_BOOKE_PID1]) >= 0) {
934 goto found_tlb;
937 if (env->spr[SPR_BOOKE_PID2] &&
938 ppcmas_tlb_check(env, tlb, raddr, address,
939 env->spr[SPR_BOOKE_PID2]) >= 0) {
940 goto found_tlb;
943 LOG_SWTLB("%s: TLB entry not found\n", __func__);
944 return -1;
946 found_tlb:
948 if (msr_pr != 0) {
949 if (tlb->mas7_3 & MAS3_UR) {
950 prot2 |= PAGE_READ;
952 if (tlb->mas7_3 & MAS3_UW) {
953 prot2 |= PAGE_WRITE;
955 if (tlb->mas7_3 & MAS3_UX) {
956 prot2 |= PAGE_EXEC;
958 } else {
959 if (tlb->mas7_3 & MAS3_SR) {
960 prot2 |= PAGE_READ;
962 if (tlb->mas7_3 & MAS3_SW) {
963 prot2 |= PAGE_WRITE;
965 if (tlb->mas7_3 & MAS3_SX) {
966 prot2 |= PAGE_EXEC;
970 /* Check the address space and permissions */
971 if (access_type == ACCESS_CODE) {
972 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
973 LOG_SWTLB("%s: AS doesn't match\n", __func__);
974 return -1;
977 *prot = prot2;
978 if (prot2 & PAGE_EXEC) {
979 LOG_SWTLB("%s: good TLB!\n", __func__);
980 return 0;
983 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
984 ret = -3;
985 } else {
986 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
987 LOG_SWTLB("%s: AS doesn't match\n", __func__);
988 return -1;
991 *prot = prot2;
992 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
993 LOG_SWTLB("%s: found TLB!\n", __func__);
994 return 0;
997 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
998 ret = -2;
1001 return ret;
1004 static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1005 target_ulong address, int rw,
1006 int access_type)
1008 ppcmas_tlb_t *tlb;
1009 hwaddr raddr;
1010 int i, j, ret;
1012 ret = -1;
1013 raddr = (hwaddr)-1ULL;
1015 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1016 int ways = booke206_tlb_ways(env, i);
1018 for (j = 0; j < ways; j++) {
1019 tlb = booke206_get_tlbm(env, i, address, j);
1020 if (!tlb) {
1021 continue;
1023 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1024 rw, access_type);
1025 if (ret != -1) {
1026 goto found_tlb;
1031 found_tlb:
1033 if (ret >= 0) {
1034 ctx->raddr = raddr;
1035 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1036 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1037 ret);
1038 } else {
1039 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1040 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1043 return ret;
1046 static const char *book3e_tsize_to_str[32] = {
1047 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1048 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1049 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1050 "1T", "2T"
1053 static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1054 CPUPPCState *env)
1056 ppcemb_tlb_t *entry;
1057 int i;
1059 if (kvm_enabled() && !env->kvm_sw_tlb) {
1060 cpu_fprintf(f, "Cannot access KVM TLB\n");
1061 return;
1064 cpu_fprintf(f, "\nTLB:\n");
1065 cpu_fprintf(f, "Effective Physical Size PID Prot "
1066 "Attr\n");
1068 entry = &env->tlb.tlbe[0];
1069 for (i = 0; i < env->nb_tlb; i++, entry++) {
1070 hwaddr ea, pa;
1071 target_ulong mask;
1072 uint64_t size = (uint64_t)entry->size;
1073 char size_buf[20];
1075 /* Check valid flag */
1076 if (!(entry->prot & PAGE_VALID)) {
1077 continue;
1080 mask = ~(entry->size - 1);
1081 ea = entry->EPN & mask;
1082 pa = entry->RPN & mask;
1083 /* Extend the physical address to 36 bits */
1084 pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1085 size /= 1024;
1086 if (size >= 1024) {
1087 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1088 } else {
1089 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1091 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1092 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1093 entry->prot, entry->attr);
1098 static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1099 CPUPPCState *env, int tlbn, int offset,
1100 int tlbsize)
1102 ppcmas_tlb_t *entry;
1103 int i;
1105 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1106 cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
1107 " URWX WIMGE U0123\n");
1109 entry = &env->tlb.tlbm[offset];
1110 for (i = 0; i < tlbsize; i++, entry++) {
1111 hwaddr ea, pa, size;
1112 int tsize;
1114 if (!(entry->mas1 & MAS1_VALID)) {
1115 continue;
1118 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1119 size = 1024ULL << tsize;
1120 ea = entry->mas2 & ~(size - 1);
1121 pa = entry->mas7_3 & ~(size - 1);
1123 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1124 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1125 (uint64_t)ea, (uint64_t)pa,
1126 book3e_tsize_to_str[tsize],
1127 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1128 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1129 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1130 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1131 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1132 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1133 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1134 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1135 entry->mas2 & MAS2_W ? 'W' : '-',
1136 entry->mas2 & MAS2_I ? 'I' : '-',
1137 entry->mas2 & MAS2_M ? 'M' : '-',
1138 entry->mas2 & MAS2_G ? 'G' : '-',
1139 entry->mas2 & MAS2_E ? 'E' : '-',
1140 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1141 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1142 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1143 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1147 static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1148 CPUPPCState *env)
1150 int offset = 0;
1151 int i;
1153 if (kvm_enabled() && !env->kvm_sw_tlb) {
1154 cpu_fprintf(f, "Cannot access KVM TLB\n");
1155 return;
1158 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1159 int size = booke206_tlb_size(env, i);
1161 if (size == 0) {
1162 continue;
1165 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1166 offset += size;
1170 static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
1171 CPUPPCState *env, int type)
1173 target_ulong *BATlt, *BATut, *BATu, *BATl;
1174 target_ulong BEPIl, BEPIu, bl;
1175 int i;
1177 switch (type) {
1178 case ACCESS_CODE:
1179 BATlt = env->IBAT[1];
1180 BATut = env->IBAT[0];
1181 break;
1182 default:
1183 BATlt = env->DBAT[1];
1184 BATut = env->DBAT[0];
1185 break;
1188 for (i = 0; i < env->nb_BATs; i++) {
1189 BATu = &BATut[i];
1190 BATl = &BATlt[i];
1191 BEPIu = *BATu & 0xF0000000;
1192 BEPIl = *BATu & 0x0FFE0000;
1193 bl = (*BATu & 0x00001FFC) << 15;
1194 cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx
1195 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
1196 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
1197 type == ACCESS_CODE ? "code" : "data", i,
1198 *BATu, *BATl, BEPIu, BEPIl, bl);
1202 static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1203 CPUPPCState *env)
1205 ppc6xx_tlb_t *tlb;
1206 target_ulong sr;
1207 int type, way, entry, i;
1209 cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
1210 cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
1212 cpu_fprintf(f, "\nSegment registers:\n");
1213 for (i = 0; i < 32; i++) {
1214 sr = env->sr[i];
1215 if (sr & 0x80000000) {
1216 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1217 "CNTLR_SPEC=0x%05x\n", i,
1218 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1219 sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
1220 (uint32_t)(sr & 0xFFFFF));
1221 } else {
1222 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
1223 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1224 sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
1225 (uint32_t)(sr & 0x00FFFFFF));
1229 cpu_fprintf(f, "\nBATs:\n");
1230 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT);
1231 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE);
1233 if (env->id_tlbs != 1) {
1234 cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB"
1235 " for code and data\n");
1238 cpu_fprintf(f, "\nTLBs [EPN EPN + SIZE]\n");
1240 for (type = 0; type < 2; type++) {
1241 for (way = 0; way < env->nb_ways; way++) {
1242 for (entry = env->nb_tlb * type + env->tlb_per_way * way;
1243 entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
1244 entry++) {
1246 tlb = &env->tlb.tlb6[entry];
1247 cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s ["
1248 TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
1249 type ? "code" : "data", entry % env->nb_tlb,
1250 env->nb_tlb, way,
1251 pte_is_valid(tlb->pte0) ? "valid" : "inval",
1252 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
1258 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1260 switch (env->mmu_model) {
1261 case POWERPC_MMU_BOOKE:
1262 mmubooke_dump_mmu(f, cpu_fprintf, env);
1263 break;
1264 case POWERPC_MMU_BOOKE206:
1265 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1266 break;
1267 case POWERPC_MMU_SOFT_6xx:
1268 case POWERPC_MMU_SOFT_74xx:
1269 mmu6xx_dump_mmu(f, cpu_fprintf, env);
1270 break;
1271 #if defined(TARGET_PPC64)
1272 case POWERPC_MMU_64B:
1273 case POWERPC_MMU_2_03:
1274 case POWERPC_MMU_2_06:
1275 case POWERPC_MMU_2_06a:
1276 case POWERPC_MMU_2_07:
1277 case POWERPC_MMU_2_07a:
1278 dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
1279 break;
1280 #endif
1281 default:
1282 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1286 static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1287 target_ulong eaddr, int rw)
1289 int in_plb, ret;
1291 ctx->raddr = eaddr;
1292 ctx->prot = PAGE_READ | PAGE_EXEC;
1293 ret = 0;
1294 switch (env->mmu_model) {
1295 case POWERPC_MMU_SOFT_6xx:
1296 case POWERPC_MMU_SOFT_74xx:
1297 case POWERPC_MMU_SOFT_4xx:
1298 case POWERPC_MMU_REAL:
1299 case POWERPC_MMU_BOOKE:
1300 ctx->prot |= PAGE_WRITE;
1301 break;
1303 case POWERPC_MMU_SOFT_4xx_Z:
1304 if (unlikely(msr_pe != 0)) {
1305 /* 403 family add some particular protections,
1306 * using PBL/PBU registers for accesses with no translation.
1308 in_plb =
1309 /* Check PLB validity */
1310 (env->pb[0] < env->pb[1] &&
1311 /* and address in plb area */
1312 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1313 (env->pb[2] < env->pb[3] &&
1314 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1315 if (in_plb ^ msr_px) {
1316 /* Access in protected area */
1317 if (rw == 1) {
1318 /* Access is not allowed */
1319 ret = -2;
1321 } else {
1322 /* Read-write access is allowed */
1323 ctx->prot |= PAGE_WRITE;
1326 break;
1328 default:
1329 /* Caller's checks mean we should never get here for other models */
1330 abort();
1331 return -1;
1334 return ret;
1337 static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1338 target_ulong eaddr, int rw, int access_type)
1340 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1341 int ret = -1;
1342 bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1343 || (access_type != ACCESS_CODE && msr_dr == 0);
1345 #if 0
1346 qemu_log("%s\n", __func__);
1347 #endif
1349 switch (env->mmu_model) {
1350 case POWERPC_MMU_SOFT_6xx:
1351 case POWERPC_MMU_SOFT_74xx:
1352 if (real_mode) {
1353 ret = check_physical(env, ctx, eaddr, rw);
1354 } else {
1355 /* Try to find a BAT */
1356 if (env->nb_BATs != 0) {
1357 ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
1359 if (ret < 0) {
1360 /* We didn't match any BAT entry or don't have BATs */
1361 ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1364 break;
1366 case POWERPC_MMU_SOFT_4xx:
1367 case POWERPC_MMU_SOFT_4xx_Z:
1368 if (real_mode) {
1369 ret = check_physical(env, ctx, eaddr, rw);
1370 } else {
1371 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1372 rw, access_type);
1374 break;
1375 case POWERPC_MMU_BOOKE:
1376 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1377 rw, access_type);
1378 break;
1379 case POWERPC_MMU_BOOKE206:
1380 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1381 access_type);
1382 break;
1383 case POWERPC_MMU_MPC8xx:
1384 /* XXX: TODO */
1385 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1386 break;
1387 case POWERPC_MMU_REAL:
1388 if (real_mode) {
1389 ret = check_physical(env, ctx, eaddr, rw);
1390 } else {
1391 cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n");
1393 return -1;
1394 default:
1395 cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
1396 return -1;
1398 #if 0
1399 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1400 __func__, eaddr, ret, ctx->raddr);
1401 #endif
1403 return ret;
1406 hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
1408 PowerPCCPU *cpu = POWERPC_CPU(cs);
1409 CPUPPCState *env = &cpu->env;
1410 mmu_ctx_t ctx;
1412 switch (env->mmu_model) {
1413 #if defined(TARGET_PPC64)
1414 case POWERPC_MMU_64B:
1415 case POWERPC_MMU_2_03:
1416 case POWERPC_MMU_2_06:
1417 case POWERPC_MMU_2_06a:
1418 case POWERPC_MMU_2_07:
1419 case POWERPC_MMU_2_07a:
1420 return ppc_hash64_get_phys_page_debug(cpu, addr);
1421 #endif
1423 case POWERPC_MMU_32B:
1424 case POWERPC_MMU_601:
1425 return ppc_hash32_get_phys_page_debug(cpu, addr);
1427 default:
1431 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1433 /* Some MMUs have separate TLBs for code and data. If we only try an
1434 * ACCESS_INT, we may not be able to read instructions mapped by code
1435 * TLBs, so we also try a ACCESS_CODE.
1437 if (unlikely(get_physical_address(env, &ctx, addr, 0,
1438 ACCESS_CODE) != 0)) {
1439 return -1;
1443 return ctx.raddr & TARGET_PAGE_MASK;
1446 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1447 int rw)
1449 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1450 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1451 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1452 env->spr[SPR_BOOKE_MAS3] = 0;
1453 env->spr[SPR_BOOKE_MAS6] = 0;
1454 env->spr[SPR_BOOKE_MAS7] = 0;
1456 /* AS */
1457 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1458 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1459 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1462 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1463 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1465 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1466 case MAS4_TIDSELD_PID0:
1467 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1468 break;
1469 case MAS4_TIDSELD_PID1:
1470 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1471 break;
1472 case MAS4_TIDSELD_PID2:
1473 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1474 break;
1477 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1479 /* next victim logic */
1480 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1481 env->last_way++;
1482 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1483 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1486 /* Perform address translation */
1487 static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
1488 int rw, int mmu_idx)
1490 CPUState *cs = CPU(ppc_env_get_cpu(env));
1491 PowerPCCPU *cpu = POWERPC_CPU(cs);
1492 mmu_ctx_t ctx;
1493 int access_type;
1494 int ret = 0;
1496 if (rw == 2) {
1497 /* code access */
1498 rw = 0;
1499 access_type = ACCESS_CODE;
1500 } else {
1501 /* data access */
1502 access_type = env->access_type;
1504 ret = get_physical_address(env, &ctx, address, rw, access_type);
1505 if (ret == 0) {
1506 tlb_set_page(cs, address & TARGET_PAGE_MASK,
1507 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1508 mmu_idx, TARGET_PAGE_SIZE);
1509 ret = 0;
1510 } else if (ret < 0) {
1511 LOG_MMU_STATE(cs);
1512 if (access_type == ACCESS_CODE) {
1513 switch (ret) {
1514 case -1:
1515 /* No matches in page tables or TLB */
1516 switch (env->mmu_model) {
1517 case POWERPC_MMU_SOFT_6xx:
1518 cs->exception_index = POWERPC_EXCP_IFTLB;
1519 env->error_code = 1 << 18;
1520 env->spr[SPR_IMISS] = address;
1521 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1522 goto tlb_miss;
1523 case POWERPC_MMU_SOFT_74xx:
1524 cs->exception_index = POWERPC_EXCP_IFTLB;
1525 goto tlb_miss_74xx;
1526 case POWERPC_MMU_SOFT_4xx:
1527 case POWERPC_MMU_SOFT_4xx_Z:
1528 cs->exception_index = POWERPC_EXCP_ITLB;
1529 env->error_code = 0;
1530 env->spr[SPR_40x_DEAR] = address;
1531 env->spr[SPR_40x_ESR] = 0x00000000;
1532 break;
1533 case POWERPC_MMU_BOOKE206:
1534 booke206_update_mas_tlb_miss(env, address, rw);
1535 /* fall through */
1536 case POWERPC_MMU_BOOKE:
1537 cs->exception_index = POWERPC_EXCP_ITLB;
1538 env->error_code = 0;
1539 env->spr[SPR_BOOKE_DEAR] = address;
1540 return -1;
1541 case POWERPC_MMU_MPC8xx:
1542 /* XXX: TODO */
1543 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1544 break;
1545 case POWERPC_MMU_REAL:
1546 cpu_abort(cs, "PowerPC in real mode should never raise "
1547 "any MMU exceptions\n");
1548 return -1;
1549 default:
1550 cpu_abort(cs, "Unknown or invalid MMU model\n");
1551 return -1;
1553 break;
1554 case -2:
1555 /* Access rights violation */
1556 cs->exception_index = POWERPC_EXCP_ISI;
1557 env->error_code = 0x08000000;
1558 break;
1559 case -3:
1560 /* No execute protection violation */
1561 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1562 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1563 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1565 cs->exception_index = POWERPC_EXCP_ISI;
1566 env->error_code = 0x10000000;
1567 break;
1568 case -4:
1569 /* Direct store exception */
1570 /* No code fetch is allowed in direct-store areas */
1571 cs->exception_index = POWERPC_EXCP_ISI;
1572 env->error_code = 0x10000000;
1573 break;
1575 } else {
1576 switch (ret) {
1577 case -1:
1578 /* No matches in page tables or TLB */
1579 switch (env->mmu_model) {
1580 case POWERPC_MMU_SOFT_6xx:
1581 if (rw == 1) {
1582 cs->exception_index = POWERPC_EXCP_DSTLB;
1583 env->error_code = 1 << 16;
1584 } else {
1585 cs->exception_index = POWERPC_EXCP_DLTLB;
1586 env->error_code = 0;
1588 env->spr[SPR_DMISS] = address;
1589 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1590 tlb_miss:
1591 env->error_code |= ctx.key << 19;
1592 env->spr[SPR_HASH1] = env->htab_base +
1593 get_pteg_offset32(cpu, ctx.hash[0]);
1594 env->spr[SPR_HASH2] = env->htab_base +
1595 get_pteg_offset32(cpu, ctx.hash[1]);
1596 break;
1597 case POWERPC_MMU_SOFT_74xx:
1598 if (rw == 1) {
1599 cs->exception_index = POWERPC_EXCP_DSTLB;
1600 } else {
1601 cs->exception_index = POWERPC_EXCP_DLTLB;
1603 tlb_miss_74xx:
1604 /* Implement LRU algorithm */
1605 env->error_code = ctx.key << 19;
1606 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1607 ((env->last_way + 1) & (env->nb_ways - 1));
1608 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1609 break;
1610 case POWERPC_MMU_SOFT_4xx:
1611 case POWERPC_MMU_SOFT_4xx_Z:
1612 cs->exception_index = POWERPC_EXCP_DTLB;
1613 env->error_code = 0;
1614 env->spr[SPR_40x_DEAR] = address;
1615 if (rw) {
1616 env->spr[SPR_40x_ESR] = 0x00800000;
1617 } else {
1618 env->spr[SPR_40x_ESR] = 0x00000000;
1620 break;
1621 case POWERPC_MMU_MPC8xx:
1622 /* XXX: TODO */
1623 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1624 break;
1625 case POWERPC_MMU_BOOKE206:
1626 booke206_update_mas_tlb_miss(env, address, rw);
1627 /* fall through */
1628 case POWERPC_MMU_BOOKE:
1629 cs->exception_index = POWERPC_EXCP_DTLB;
1630 env->error_code = 0;
1631 env->spr[SPR_BOOKE_DEAR] = address;
1632 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1633 return -1;
1634 case POWERPC_MMU_REAL:
1635 cpu_abort(cs, "PowerPC in real mode should never raise "
1636 "any MMU exceptions\n");
1637 return -1;
1638 default:
1639 cpu_abort(cs, "Unknown or invalid MMU model\n");
1640 return -1;
1642 break;
1643 case -2:
1644 /* Access rights violation */
1645 cs->exception_index = POWERPC_EXCP_DSI;
1646 env->error_code = 0;
1647 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1648 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1649 env->spr[SPR_40x_DEAR] = address;
1650 if (rw) {
1651 env->spr[SPR_40x_ESR] |= 0x00800000;
1653 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1654 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1655 env->spr[SPR_BOOKE_DEAR] = address;
1656 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1657 } else {
1658 env->spr[SPR_DAR] = address;
1659 if (rw == 1) {
1660 env->spr[SPR_DSISR] = 0x0A000000;
1661 } else {
1662 env->spr[SPR_DSISR] = 0x08000000;
1665 break;
1666 case -4:
1667 /* Direct store exception */
1668 switch (access_type) {
1669 case ACCESS_FLOAT:
1670 /* Floating point load/store */
1671 cs->exception_index = POWERPC_EXCP_ALIGN;
1672 env->error_code = POWERPC_EXCP_ALIGN_FP;
1673 env->spr[SPR_DAR] = address;
1674 break;
1675 case ACCESS_RES:
1676 /* lwarx, ldarx or stwcx. */
1677 cs->exception_index = POWERPC_EXCP_DSI;
1678 env->error_code = 0;
1679 env->spr[SPR_DAR] = address;
1680 if (rw == 1) {
1681 env->spr[SPR_DSISR] = 0x06000000;
1682 } else {
1683 env->spr[SPR_DSISR] = 0x04000000;
1685 break;
1686 case ACCESS_EXT:
1687 /* eciwx or ecowx */
1688 cs->exception_index = POWERPC_EXCP_DSI;
1689 env->error_code = 0;
1690 env->spr[SPR_DAR] = address;
1691 if (rw == 1) {
1692 env->spr[SPR_DSISR] = 0x06100000;
1693 } else {
1694 env->spr[SPR_DSISR] = 0x04100000;
1696 break;
1697 default:
1698 printf("DSI: invalid exception (%d)\n", ret);
1699 cs->exception_index = POWERPC_EXCP_PROGRAM;
1700 env->error_code =
1701 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1702 env->spr[SPR_DAR] = address;
1703 break;
1705 break;
1708 #if 0
1709 printf("%s: set exception to %d %02x\n", __func__,
1710 cs->exception, env->error_code);
1711 #endif
1712 ret = 1;
1715 return ret;
1718 /*****************************************************************************/
1719 /* BATs management */
1720 #if !defined(FLUSH_ALL_TLBS)
1721 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1722 target_ulong mask)
1724 CPUState *cs = CPU(ppc_env_get_cpu(env));
1725 target_ulong base, end, page;
1727 base = BATu & ~0x0001FFFF;
1728 end = base + mask + 0x00020000;
1729 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1730 TARGET_FMT_lx ")\n", base, end, mask);
1731 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
1732 tlb_flush_page(cs, page);
1734 LOG_BATS("Flush done\n");
1736 #endif
1738 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1739 target_ulong value)
1741 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1742 nr, ul == 0 ? 'u' : 'l', value, env->nip);
1745 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1747 target_ulong mask;
1749 dump_store_bat(env, 'I', 0, nr, value);
1750 if (env->IBAT[0][nr] != value) {
1751 mask = (value << 15) & 0x0FFE0000UL;
1752 #if !defined(FLUSH_ALL_TLBS)
1753 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1754 #endif
1755 /* When storing valid upper BAT, mask BEPI and BRPN
1756 * and invalidate all TLBs covered by this BAT
1758 mask = (value << 15) & 0x0FFE0000UL;
1759 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1760 (value & ~0x0001FFFFUL & ~mask);
1761 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1762 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1763 #if !defined(FLUSH_ALL_TLBS)
1764 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1765 #else
1766 tlb_flush(env, 1);
1767 #endif
1771 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1773 dump_store_bat(env, 'I', 1, nr, value);
1774 env->IBAT[1][nr] = value;
1777 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1779 target_ulong mask;
1781 dump_store_bat(env, 'D', 0, nr, value);
1782 if (env->DBAT[0][nr] != value) {
1783 /* When storing valid upper BAT, mask BEPI and BRPN
1784 * and invalidate all TLBs covered by this BAT
1786 mask = (value << 15) & 0x0FFE0000UL;
1787 #if !defined(FLUSH_ALL_TLBS)
1788 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1789 #endif
1790 mask = (value << 15) & 0x0FFE0000UL;
1791 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1792 (value & ~0x0001FFFFUL & ~mask);
1793 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1794 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1795 #if !defined(FLUSH_ALL_TLBS)
1796 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1797 #else
1798 tlb_flush(env, 1);
1799 #endif
1803 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1805 dump_store_bat(env, 'D', 1, nr, value);
1806 env->DBAT[1][nr] = value;
1809 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
1811 target_ulong mask;
1812 #if defined(FLUSH_ALL_TLBS)
1813 int do_inval;
1814 #endif
1816 dump_store_bat(env, 'I', 0, nr, value);
1817 if (env->IBAT[0][nr] != value) {
1818 #if defined(FLUSH_ALL_TLBS)
1819 do_inval = 0;
1820 #endif
1821 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1822 if (env->IBAT[1][nr] & 0x40) {
1823 /* Invalidate BAT only if it is valid */
1824 #if !defined(FLUSH_ALL_TLBS)
1825 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1826 #else
1827 do_inval = 1;
1828 #endif
1830 /* When storing valid upper BAT, mask BEPI and BRPN
1831 * and invalidate all TLBs covered by this BAT
1833 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1834 (value & ~0x0001FFFFUL & ~mask);
1835 env->DBAT[0][nr] = env->IBAT[0][nr];
1836 if (env->IBAT[1][nr] & 0x40) {
1837 #if !defined(FLUSH_ALL_TLBS)
1838 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1839 #else
1840 do_inval = 1;
1841 #endif
1843 #if defined(FLUSH_ALL_TLBS)
1844 if (do_inval) {
1845 tlb_flush(env, 1);
1847 #endif
1851 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
1853 #if !defined(FLUSH_ALL_TLBS)
1854 target_ulong mask;
1855 #else
1856 int do_inval;
1857 #endif
1859 dump_store_bat(env, 'I', 1, nr, value);
1860 if (env->IBAT[1][nr] != value) {
1861 #if defined(FLUSH_ALL_TLBS)
1862 do_inval = 0;
1863 #endif
1864 if (env->IBAT[1][nr] & 0x40) {
1865 #if !defined(FLUSH_ALL_TLBS)
1866 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1867 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1868 #else
1869 do_inval = 1;
1870 #endif
1872 if (value & 0x40) {
1873 #if !defined(FLUSH_ALL_TLBS)
1874 mask = (value << 17) & 0x0FFE0000UL;
1875 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1876 #else
1877 do_inval = 1;
1878 #endif
1880 env->IBAT[1][nr] = value;
1881 env->DBAT[1][nr] = value;
1882 #if defined(FLUSH_ALL_TLBS)
1883 if (do_inval) {
1884 tlb_flush(env, 1);
1886 #endif
1890 /*****************************************************************************/
1891 /* TLB management */
1892 void ppc_tlb_invalidate_all(CPUPPCState *env)
1894 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1896 switch (env->mmu_model) {
1897 case POWERPC_MMU_SOFT_6xx:
1898 case POWERPC_MMU_SOFT_74xx:
1899 ppc6xx_tlb_invalidate_all(env);
1900 break;
1901 case POWERPC_MMU_SOFT_4xx:
1902 case POWERPC_MMU_SOFT_4xx_Z:
1903 ppc4xx_tlb_invalidate_all(env);
1904 break;
1905 case POWERPC_MMU_REAL:
1906 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1907 break;
1908 case POWERPC_MMU_MPC8xx:
1909 /* XXX: TODO */
1910 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1911 break;
1912 case POWERPC_MMU_BOOKE:
1913 tlb_flush(CPU(cpu), 1);
1914 break;
1915 case POWERPC_MMU_BOOKE206:
1916 booke206_flush_tlb(env, -1, 0);
1917 break;
1918 case POWERPC_MMU_32B:
1919 case POWERPC_MMU_601:
1920 #if defined(TARGET_PPC64)
1921 case POWERPC_MMU_64B:
1922 case POWERPC_MMU_2_03:
1923 case POWERPC_MMU_2_06:
1924 case POWERPC_MMU_2_06a:
1925 case POWERPC_MMU_2_07:
1926 case POWERPC_MMU_2_07a:
1927 #endif /* defined(TARGET_PPC64) */
1928 tlb_flush(CPU(cpu), 1);
1929 break;
1930 default:
1931 /* XXX: TODO */
1932 cpu_abort(CPU(cpu), "Unknown MMU model\n");
1933 break;
1937 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
1939 #if !defined(FLUSH_ALL_TLBS)
1940 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1941 CPUState *cs;
1943 addr &= TARGET_PAGE_MASK;
1944 switch (env->mmu_model) {
1945 case POWERPC_MMU_SOFT_6xx:
1946 case POWERPC_MMU_SOFT_74xx:
1947 ppc6xx_tlb_invalidate_virt(env, addr, 0);
1948 if (env->id_tlbs == 1) {
1949 ppc6xx_tlb_invalidate_virt(env, addr, 1);
1951 break;
1952 case POWERPC_MMU_32B:
1953 case POWERPC_MMU_601:
1954 /* tlbie invalidate TLBs for all segments */
1955 addr &= ~((target_ulong)-1ULL << 28);
1956 cs = CPU(cpu);
1957 /* XXX: this case should be optimized,
1958 * giving a mask to tlb_flush_page
1960 tlb_flush_page(cs, addr | (0x0 << 28));
1961 tlb_flush_page(cs, addr | (0x1 << 28));
1962 tlb_flush_page(cs, addr | (0x2 << 28));
1963 tlb_flush_page(cs, addr | (0x3 << 28));
1964 tlb_flush_page(cs, addr | (0x4 << 28));
1965 tlb_flush_page(cs, addr | (0x5 << 28));
1966 tlb_flush_page(cs, addr | (0x6 << 28));
1967 tlb_flush_page(cs, addr | (0x7 << 28));
1968 tlb_flush_page(cs, addr | (0x8 << 28));
1969 tlb_flush_page(cs, addr | (0x9 << 28));
1970 tlb_flush_page(cs, addr | (0xA << 28));
1971 tlb_flush_page(cs, addr | (0xB << 28));
1972 tlb_flush_page(cs, addr | (0xC << 28));
1973 tlb_flush_page(cs, addr | (0xD << 28));
1974 tlb_flush_page(cs, addr | (0xE << 28));
1975 tlb_flush_page(cs, addr | (0xF << 28));
1976 break;
1977 #if defined(TARGET_PPC64)
1978 case POWERPC_MMU_64B:
1979 case POWERPC_MMU_2_03:
1980 case POWERPC_MMU_2_06:
1981 case POWERPC_MMU_2_06a:
1982 case POWERPC_MMU_2_07:
1983 case POWERPC_MMU_2_07a:
1984 /* tlbie invalidate TLBs for all segments */
1985 /* XXX: given the fact that there are too many segments to invalidate,
1986 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
1987 * we just invalidate all TLBs
1989 tlb_flush(CPU(cpu), 1);
1990 break;
1991 #endif /* defined(TARGET_PPC64) */
1992 default:
1993 /* Should never reach here with other MMU models */
1994 assert(0);
1996 #else
1997 ppc_tlb_invalidate_all(env);
1998 #endif
2001 /*****************************************************************************/
2002 /* Special registers manipulation */
2003 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2005 qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
2006 assert(!env->external_htab);
2007 env->spr[SPR_SDR1] = value;
2008 #if defined(TARGET_PPC64)
2009 if (env->mmu_model & POWERPC_MMU_64) {
2010 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2011 Error *local_err = NULL;
2013 ppc_hash64_set_sdr1(cpu, value, &local_err);
2014 if (local_err) {
2015 error_report_err(local_err);
2016 error_free(local_err);
2018 } else
2019 #endif /* defined(TARGET_PPC64) */
2021 /* FIXME: Should check for valid HTABMASK values */
2022 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2023 env->htab_base = value & SDR_32_HTABORG;
2027 /* Segment registers load and store */
2028 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2030 #if defined(TARGET_PPC64)
2031 if (env->mmu_model & POWERPC_MMU_64) {
2032 /* XXX */
2033 return 0;
2035 #endif
2036 return env->sr[sr_num];
2039 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2041 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2043 qemu_log_mask(CPU_LOG_MMU,
2044 "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2045 (int)srnum, value, env->sr[srnum]);
2046 #if defined(TARGET_PPC64)
2047 if (env->mmu_model & POWERPC_MMU_64) {
2048 uint64_t esid, vsid;
2050 /* ESID = srnum */
2051 esid = ((uint64_t)(srnum & 0xf) << 28) | SLB_ESID_V;
2053 /* VSID = VSID */
2054 vsid = (value & 0xfffffff) << 12;
2055 /* flags = flags */
2056 vsid |= ((value >> 27) & 0xf) << 8;
2058 ppc_store_slb(cpu, srnum, esid, vsid);
2059 } else
2060 #endif
2061 if (env->sr[srnum] != value) {
2062 env->sr[srnum] = value;
2063 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2064 flusing the whole TLB. */
2065 #if !defined(FLUSH_ALL_TLBS) && 0
2067 target_ulong page, end;
2068 /* Invalidate 256 MB of virtual memory */
2069 page = (16 << 20) * srnum;
2070 end = page + (16 << 20);
2071 for (; page != end; page += TARGET_PAGE_SIZE) {
2072 tlb_flush_page(CPU(cpu), page);
2075 #else
2076 tlb_flush(CPU(cpu), 1);
2077 #endif
2081 /* TLB management */
2082 void helper_tlbia(CPUPPCState *env)
2084 ppc_tlb_invalidate_all(env);
2087 void helper_tlbie(CPUPPCState *env, target_ulong addr)
2089 ppc_tlb_invalidate_one(env, addr);
2092 void helper_tlbiva(CPUPPCState *env, target_ulong addr)
2094 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2096 /* tlbiva instruction only exists on BookE */
2097 assert(env->mmu_model == POWERPC_MMU_BOOKE);
2098 /* XXX: TODO */
2099 cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
2102 /* Software driven TLBs management */
2103 /* PowerPC 602/603 software TLB load instructions helpers */
2104 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2106 target_ulong RPN, CMP, EPN;
2107 int way;
2109 RPN = env->spr[SPR_RPA];
2110 if (is_code) {
2111 CMP = env->spr[SPR_ICMP];
2112 EPN = env->spr[SPR_IMISS];
2113 } else {
2114 CMP = env->spr[SPR_DCMP];
2115 EPN = env->spr[SPR_DMISS];
2117 way = (env->spr[SPR_SRR1] >> 17) & 1;
2118 (void)EPN; /* avoid a compiler warning */
2119 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2120 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2121 RPN, way);
2122 /* Store this TLB */
2123 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2124 way, is_code, CMP, RPN);
2127 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2129 do_6xx_tlb(env, EPN, 0);
2132 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2134 do_6xx_tlb(env, EPN, 1);
2137 /* PowerPC 74xx software TLB load instructions helpers */
2138 static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2140 target_ulong RPN, CMP, EPN;
2141 int way;
2143 RPN = env->spr[SPR_PTELO];
2144 CMP = env->spr[SPR_PTEHI];
2145 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2146 way = env->spr[SPR_TLBMISS] & 0x3;
2147 (void)EPN; /* avoid a compiler warning */
2148 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2149 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2150 RPN, way);
2151 /* Store this TLB */
2152 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2153 way, is_code, CMP, RPN);
2156 void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2158 do_74xx_tlb(env, EPN, 0);
2161 void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2163 do_74xx_tlb(env, EPN, 1);
2166 /*****************************************************************************/
2167 /* PowerPC 601 specific instructions (POWER bridge) */
2169 target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2171 mmu_ctx_t ctx;
2172 int nb_BATs;
2173 target_ulong ret = 0;
2175 /* We don't have to generate many instances of this instruction,
2176 * as rac is supervisor only.
2178 /* XXX: FIX THIS: Pretend we have no BAT */
2179 nb_BATs = env->nb_BATs;
2180 env->nb_BATs = 0;
2181 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2182 ret = ctx.raddr;
2184 env->nb_BATs = nb_BATs;
2185 return ret;
2188 static inline target_ulong booke_tlb_to_page_size(int size)
2190 return 1024 << (2 * size);
2193 static inline int booke_page_size_to_tlb(target_ulong page_size)
2195 int size;
2197 switch (page_size) {
2198 case 0x00000400UL:
2199 size = 0x0;
2200 break;
2201 case 0x00001000UL:
2202 size = 0x1;
2203 break;
2204 case 0x00004000UL:
2205 size = 0x2;
2206 break;
2207 case 0x00010000UL:
2208 size = 0x3;
2209 break;
2210 case 0x00040000UL:
2211 size = 0x4;
2212 break;
2213 case 0x00100000UL:
2214 size = 0x5;
2215 break;
2216 case 0x00400000UL:
2217 size = 0x6;
2218 break;
2219 case 0x01000000UL:
2220 size = 0x7;
2221 break;
2222 case 0x04000000UL:
2223 size = 0x8;
2224 break;
2225 case 0x10000000UL:
2226 size = 0x9;
2227 break;
2228 case 0x40000000UL:
2229 size = 0xA;
2230 break;
2231 #if defined(TARGET_PPC64)
2232 case 0x000100000000ULL:
2233 size = 0xB;
2234 break;
2235 case 0x000400000000ULL:
2236 size = 0xC;
2237 break;
2238 case 0x001000000000ULL:
2239 size = 0xD;
2240 break;
2241 case 0x004000000000ULL:
2242 size = 0xE;
2243 break;
2244 case 0x010000000000ULL:
2245 size = 0xF;
2246 break;
2247 #endif
2248 default:
2249 size = -1;
2250 break;
2253 return size;
2256 /* Helpers for 4xx TLB management */
2257 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2259 #define PPC4XX_TLBHI_V 0x00000040
2260 #define PPC4XX_TLBHI_E 0x00000020
2261 #define PPC4XX_TLBHI_SIZE_MIN 0
2262 #define PPC4XX_TLBHI_SIZE_MAX 7
2263 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2264 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2265 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2267 #define PPC4XX_TLBLO_EX 0x00000200
2268 #define PPC4XX_TLBLO_WR 0x00000100
2269 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2270 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2272 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2274 ppcemb_tlb_t *tlb;
2275 target_ulong ret;
2276 int size;
2278 entry &= PPC4XX_TLB_ENTRY_MASK;
2279 tlb = &env->tlb.tlbe[entry];
2280 ret = tlb->EPN;
2281 if (tlb->prot & PAGE_VALID) {
2282 ret |= PPC4XX_TLBHI_V;
2284 size = booke_page_size_to_tlb(tlb->size);
2285 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2286 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2288 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2289 env->spr[SPR_40x_PID] = tlb->PID;
2290 return ret;
2293 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2295 ppcemb_tlb_t *tlb;
2296 target_ulong ret;
2298 entry &= PPC4XX_TLB_ENTRY_MASK;
2299 tlb = &env->tlb.tlbe[entry];
2300 ret = tlb->RPN;
2301 if (tlb->prot & PAGE_EXEC) {
2302 ret |= PPC4XX_TLBLO_EX;
2304 if (tlb->prot & PAGE_WRITE) {
2305 ret |= PPC4XX_TLBLO_WR;
2307 return ret;
2310 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2311 target_ulong val)
2313 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2314 CPUState *cs = CPU(cpu);
2315 ppcemb_tlb_t *tlb;
2316 target_ulong page, end;
2318 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2319 val);
2320 entry &= PPC4XX_TLB_ENTRY_MASK;
2321 tlb = &env->tlb.tlbe[entry];
2322 /* Invalidate previous TLB (if it's valid) */
2323 if (tlb->prot & PAGE_VALID) {
2324 end = tlb->EPN + tlb->size;
2325 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2326 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2327 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2328 tlb_flush_page(cs, page);
2331 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2332 & PPC4XX_TLBHI_SIZE_MASK);
2333 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2334 * If this ever occurs, one should use the ppcemb target instead
2335 * of the ppc or ppc64 one
2337 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2338 cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
2339 "are not supported (%d)\n",
2340 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2342 tlb->EPN = val & ~(tlb->size - 1);
2343 if (val & PPC4XX_TLBHI_V) {
2344 tlb->prot |= PAGE_VALID;
2345 if (val & PPC4XX_TLBHI_E) {
2346 /* XXX: TO BE FIXED */
2347 cpu_abort(cs,
2348 "Little-endian TLB entries are not supported by now\n");
2350 } else {
2351 tlb->prot &= ~PAGE_VALID;
2353 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2354 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2355 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2356 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2357 tlb->prot & PAGE_READ ? 'r' : '-',
2358 tlb->prot & PAGE_WRITE ? 'w' : '-',
2359 tlb->prot & PAGE_EXEC ? 'x' : '-',
2360 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2361 /* Invalidate new TLB (if valid) */
2362 if (tlb->prot & PAGE_VALID) {
2363 end = tlb->EPN + tlb->size;
2364 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2365 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2366 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2367 tlb_flush_page(cs, page);
2372 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2373 target_ulong val)
2375 ppcemb_tlb_t *tlb;
2377 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2378 val);
2379 entry &= PPC4XX_TLB_ENTRY_MASK;
2380 tlb = &env->tlb.tlbe[entry];
2381 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2382 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2383 tlb->prot = PAGE_READ;
2384 if (val & PPC4XX_TLBLO_EX) {
2385 tlb->prot |= PAGE_EXEC;
2387 if (val & PPC4XX_TLBLO_WR) {
2388 tlb->prot |= PAGE_WRITE;
2390 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2391 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2392 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2393 tlb->prot & PAGE_READ ? 'r' : '-',
2394 tlb->prot & PAGE_WRITE ? 'w' : '-',
2395 tlb->prot & PAGE_EXEC ? 'x' : '-',
2396 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2399 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2401 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2404 /* PowerPC 440 TLB management */
2405 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2406 target_ulong value)
2408 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2409 ppcemb_tlb_t *tlb;
2410 target_ulong EPN, RPN, size;
2411 int do_flush_tlbs;
2413 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2414 __func__, word, (int)entry, value);
2415 do_flush_tlbs = 0;
2416 entry &= 0x3F;
2417 tlb = &env->tlb.tlbe[entry];
2418 switch (word) {
2419 default:
2420 /* Just here to please gcc */
2421 case 0:
2422 EPN = value & 0xFFFFFC00;
2423 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2424 do_flush_tlbs = 1;
2426 tlb->EPN = EPN;
2427 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2428 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2429 do_flush_tlbs = 1;
2431 tlb->size = size;
2432 tlb->attr &= ~0x1;
2433 tlb->attr |= (value >> 8) & 1;
2434 if (value & 0x200) {
2435 tlb->prot |= PAGE_VALID;
2436 } else {
2437 if (tlb->prot & PAGE_VALID) {
2438 tlb->prot &= ~PAGE_VALID;
2439 do_flush_tlbs = 1;
2442 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2443 if (do_flush_tlbs) {
2444 tlb_flush(CPU(cpu), 1);
2446 break;
2447 case 1:
2448 RPN = value & 0xFFFFFC0F;
2449 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2450 tlb_flush(CPU(cpu), 1);
2452 tlb->RPN = RPN;
2453 break;
2454 case 2:
2455 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2456 tlb->prot = tlb->prot & PAGE_VALID;
2457 if (value & 0x1) {
2458 tlb->prot |= PAGE_READ << 4;
2460 if (value & 0x2) {
2461 tlb->prot |= PAGE_WRITE << 4;
2463 if (value & 0x4) {
2464 tlb->prot |= PAGE_EXEC << 4;
2466 if (value & 0x8) {
2467 tlb->prot |= PAGE_READ;
2469 if (value & 0x10) {
2470 tlb->prot |= PAGE_WRITE;
2472 if (value & 0x20) {
2473 tlb->prot |= PAGE_EXEC;
2475 break;
2479 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2480 target_ulong entry)
2482 ppcemb_tlb_t *tlb;
2483 target_ulong ret;
2484 int size;
2486 entry &= 0x3F;
2487 tlb = &env->tlb.tlbe[entry];
2488 switch (word) {
2489 default:
2490 /* Just here to please gcc */
2491 case 0:
2492 ret = tlb->EPN;
2493 size = booke_page_size_to_tlb(tlb->size);
2494 if (size < 0 || size > 0xF) {
2495 size = 1;
2497 ret |= size << 4;
2498 if (tlb->attr & 0x1) {
2499 ret |= 0x100;
2501 if (tlb->prot & PAGE_VALID) {
2502 ret |= 0x200;
2504 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2505 env->spr[SPR_440_MMUCR] |= tlb->PID;
2506 break;
2507 case 1:
2508 ret = tlb->RPN;
2509 break;
2510 case 2:
2511 ret = tlb->attr & ~0x1;
2512 if (tlb->prot & (PAGE_READ << 4)) {
2513 ret |= 0x1;
2515 if (tlb->prot & (PAGE_WRITE << 4)) {
2516 ret |= 0x2;
2518 if (tlb->prot & (PAGE_EXEC << 4)) {
2519 ret |= 0x4;
2521 if (tlb->prot & PAGE_READ) {
2522 ret |= 0x8;
2524 if (tlb->prot & PAGE_WRITE) {
2525 ret |= 0x10;
2527 if (tlb->prot & PAGE_EXEC) {
2528 ret |= 0x20;
2530 break;
2532 return ret;
2535 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2537 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2540 /* PowerPC BookE 2.06 TLB management */
2542 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2544 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2545 uint32_t tlbncfg = 0;
2546 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2547 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2548 int tlb;
2550 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2551 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2553 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2554 cpu_abort(CPU(cpu), "we don't support HES yet\n");
2557 return booke206_get_tlbm(env, tlb, ea, esel);
2560 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2562 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2564 env->spr[pidn] = pid;
2565 /* changing PIDs mean we're in a different address space now */
2566 tlb_flush(CPU(cpu), 1);
2569 void helper_booke206_tlbwe(CPUPPCState *env)
2571 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2572 uint32_t tlbncfg, tlbn;
2573 ppcmas_tlb_t *tlb;
2574 uint32_t size_tlb, size_ps;
2575 target_ulong mask;
2578 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2579 case MAS0_WQ_ALWAYS:
2580 /* good to go, write that entry */
2581 break;
2582 case MAS0_WQ_COND:
2583 /* XXX check if reserved */
2584 if (0) {
2585 return;
2587 break;
2588 case MAS0_WQ_CLR_RSRV:
2589 /* XXX clear entry */
2590 return;
2591 default:
2592 /* no idea what to do */
2593 return;
2596 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2597 !msr_gs) {
2598 /* XXX we don't support direct LRAT setting yet */
2599 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2600 return;
2603 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2604 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2606 tlb = booke206_cur_tlb(env);
2608 if (!tlb) {
2609 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2610 POWERPC_EXCP_INVAL |
2611 POWERPC_EXCP_INVAL_INVAL);
2614 /* check that we support the targeted size */
2615 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2616 size_ps = booke206_tlbnps(env, tlbn);
2617 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2618 !(size_ps & (1 << size_tlb))) {
2619 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2620 POWERPC_EXCP_INVAL |
2621 POWERPC_EXCP_INVAL_INVAL);
2624 if (msr_gs) {
2625 cpu_abort(CPU(cpu), "missing HV implementation\n");
2627 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2628 env->spr[SPR_BOOKE_MAS3];
2629 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2631 /* MAV 1.0 only */
2632 if (!(tlbncfg & TLBnCFG_AVAIL)) {
2633 /* force !AVAIL TLB entries to correct page size */
2634 tlb->mas1 &= ~MAS1_TSIZE_MASK;
2635 /* XXX can be configured in MMUCSR0 */
2636 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2639 /* Make a mask from TLB size to discard invalid bits in EPN field */
2640 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2641 /* Add a mask for page attributes */
2642 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2644 if (!msr_cm) {
2645 /* Executing a tlbwe instruction in 32-bit mode will set
2646 * bits 0:31 of the TLB EPN field to zero.
2648 mask &= 0xffffffff;
2651 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
2653 if (!(tlbncfg & TLBnCFG_IPROT)) {
2654 /* no IPROT supported by TLB */
2655 tlb->mas1 &= ~MAS1_IPROT;
2658 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
2659 tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
2660 } else {
2661 tlb_flush(CPU(cpu), 1);
2665 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2667 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2668 int way = booke206_tlbm_to_way(env, tlb);
2670 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2671 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2672 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2674 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2675 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2676 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2677 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2680 void helper_booke206_tlbre(CPUPPCState *env)
2682 ppcmas_tlb_t *tlb = NULL;
2684 tlb = booke206_cur_tlb(env);
2685 if (!tlb) {
2686 env->spr[SPR_BOOKE_MAS1] = 0;
2687 } else {
2688 booke206_tlb_to_mas(env, tlb);
2692 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
2694 ppcmas_tlb_t *tlb = NULL;
2695 int i, j;
2696 hwaddr raddr;
2697 uint32_t spid, sas;
2699 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2700 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2702 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2703 int ways = booke206_tlb_ways(env, i);
2705 for (j = 0; j < ways; j++) {
2706 tlb = booke206_get_tlbm(env, i, address, j);
2708 if (!tlb) {
2709 continue;
2712 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2713 continue;
2716 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2717 continue;
2720 booke206_tlb_to_mas(env, tlb);
2721 return;
2725 /* no entry found, fill with defaults */
2726 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2727 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2728 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2729 env->spr[SPR_BOOKE_MAS3] = 0;
2730 env->spr[SPR_BOOKE_MAS7] = 0;
2732 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2733 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2736 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2737 << MAS1_TID_SHIFT;
2739 /* next victim logic */
2740 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2741 env->last_way++;
2742 env->last_way &= booke206_tlb_ways(env, 0) - 1;
2743 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2746 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2747 uint32_t ea)
2749 int i;
2750 int ways = booke206_tlb_ways(env, tlbn);
2751 target_ulong mask;
2753 for (i = 0; i < ways; i++) {
2754 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2755 if (!tlb) {
2756 continue;
2758 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2759 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2760 !(tlb->mas1 & MAS1_IPROT)) {
2761 tlb->mas1 &= ~MAS1_VALID;
2766 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
2768 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2770 if (address & 0x4) {
2771 /* flush all entries */
2772 if (address & 0x8) {
2773 /* flush all of TLB1 */
2774 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2775 } else {
2776 /* flush all of TLB0 */
2777 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2779 return;
2782 if (address & 0x8) {
2783 /* flush TLB1 entries */
2784 booke206_invalidate_ea_tlb(env, 1, address);
2785 tlb_flush(CPU(cpu), 1);
2786 } else {
2787 /* flush TLB0 entries */
2788 booke206_invalidate_ea_tlb(env, 0, address);
2789 tlb_flush_page(CPU(cpu), address & MAS2_EPN_MASK);
2793 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
2795 /* XXX missing LPID handling */
2796 booke206_flush_tlb(env, -1, 1);
2799 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
2801 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2802 int i, j;
2803 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2804 ppcmas_tlb_t *tlb = env->tlb.tlbm;
2805 int tlb_size;
2807 /* XXX missing LPID handling */
2808 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2809 tlb_size = booke206_tlb_size(env, i);
2810 for (j = 0; j < tlb_size; j++) {
2811 if (!(tlb[j].mas1 & MAS1_IPROT) &&
2812 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2813 tlb[j].mas1 &= ~MAS1_VALID;
2816 tlb += booke206_tlb_size(env, i);
2818 tlb_flush(CPU(cpu), 1);
2821 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
2823 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2824 int i, j;
2825 ppcmas_tlb_t *tlb;
2826 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2827 int pid = tid >> MAS6_SPID_SHIFT;
2828 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2829 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
2830 /* XXX check for unsupported isize and raise an invalid opcode then */
2831 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
2832 /* XXX implement MAV2 handling */
2833 bool mav2 = false;
2835 /* XXX missing LPID handling */
2836 /* flush by pid and ea */
2837 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2838 int ways = booke206_tlb_ways(env, i);
2840 for (j = 0; j < ways; j++) {
2841 tlb = booke206_get_tlbm(env, i, address, j);
2842 if (!tlb) {
2843 continue;
2845 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
2846 (tlb->mas1 & MAS1_IPROT) ||
2847 ((tlb->mas1 & MAS1_IND) != ind) ||
2848 ((tlb->mas8 & MAS8_TGS) != sgs)) {
2849 continue;
2851 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
2852 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2853 continue;
2855 /* XXX e500mc doesn't match SAS, but other cores might */
2856 tlb->mas1 &= ~MAS1_VALID;
2859 tlb_flush(CPU(cpu), 1);
2862 void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
2864 int flags = 0;
2866 if (type & 2) {
2867 flags |= BOOKE206_FLUSH_TLB1;
2870 if (type & 4) {
2871 flags |= BOOKE206_FLUSH_TLB0;
2874 booke206_flush_tlb(env, flags, 1);
2878 /*****************************************************************************/
2880 /* try to fill the TLB and return an exception if error. If retaddr is
2881 NULL, it means that the function was called in C code (i.e. not
2882 from generated code or from helper.c) */
2883 /* XXX: fix it to restore all registers */
2884 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
2885 uintptr_t retaddr)
2887 PowerPCCPU *cpu = POWERPC_CPU(cs);
2888 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
2889 CPUPPCState *env = &cpu->env;
2890 int ret;
2892 if (pcc->handle_mmu_fault) {
2893 ret = pcc->handle_mmu_fault(cpu, addr, is_write, mmu_idx);
2894 } else {
2895 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
2897 if (unlikely(ret != 0)) {
2898 if (likely(retaddr)) {
2899 /* now we have a real cpu fault */
2900 cpu_restore_state(cs, retaddr);
2902 helper_raise_exception_err(env, cs->exception_index, env->error_code);