xref: /openbmc/qemu/target/ppc/mmu_common.c (revision 306b5320307d13e95e1d43b585879cb56b163f66)
15118ebe8SLucas Mateus Castro (alqotel) /*
25118ebe8SLucas Mateus Castro (alqotel)  *  PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
35118ebe8SLucas Mateus Castro (alqotel)  *
45118ebe8SLucas Mateus Castro (alqotel)  *  Copyright (c) 2003-2007 Jocelyn Mayer
55118ebe8SLucas Mateus Castro (alqotel)  *
65118ebe8SLucas Mateus Castro (alqotel)  * This library is free software; you can redistribute it and/or
75118ebe8SLucas Mateus Castro (alqotel)  * modify it under the terms of the GNU Lesser General Public
85118ebe8SLucas Mateus Castro (alqotel)  * License as published by the Free Software Foundation; either
95118ebe8SLucas Mateus Castro (alqotel)  * version 2.1 of the License, or (at your option) any later version.
105118ebe8SLucas Mateus Castro (alqotel)  *
115118ebe8SLucas Mateus Castro (alqotel)  * This library is distributed in the hope that it will be useful,
125118ebe8SLucas Mateus Castro (alqotel)  * but WITHOUT ANY WARRANTY; without even the implied warranty of
135118ebe8SLucas Mateus Castro (alqotel)  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
145118ebe8SLucas Mateus Castro (alqotel)  * Lesser General Public License for more details.
155118ebe8SLucas Mateus Castro (alqotel)  *
165118ebe8SLucas Mateus Castro (alqotel)  * You should have received a copy of the GNU Lesser General Public
175118ebe8SLucas Mateus Castro (alqotel)  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
185118ebe8SLucas Mateus Castro (alqotel)  */
195118ebe8SLucas Mateus Castro (alqotel) 
205118ebe8SLucas Mateus Castro (alqotel) #include "qemu/osdep.h"
215118ebe8SLucas Mateus Castro (alqotel) #include "qemu/units.h"
225118ebe8SLucas Mateus Castro (alqotel) #include "cpu.h"
235118ebe8SLucas Mateus Castro (alqotel) #include "sysemu/kvm.h"
245118ebe8SLucas Mateus Castro (alqotel) #include "kvm_ppc.h"
255118ebe8SLucas Mateus Castro (alqotel) #include "mmu-hash64.h"
265118ebe8SLucas Mateus Castro (alqotel) #include "mmu-hash32.h"
275118ebe8SLucas Mateus Castro (alqotel) #include "exec/exec-all.h"
2874781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
295118ebe8SLucas Mateus Castro (alqotel) #include "exec/log.h"
305118ebe8SLucas Mateus Castro (alqotel) #include "helper_regs.h"
315118ebe8SLucas Mateus Castro (alqotel) #include "qemu/error-report.h"
325118ebe8SLucas Mateus Castro (alqotel) #include "qemu/qemu-print.h"
335118ebe8SLucas Mateus Castro (alqotel) #include "internal.h"
345118ebe8SLucas Mateus Castro (alqotel) #include "mmu-book3s-v3.h"
355118ebe8SLucas Mateus Castro (alqotel) #include "mmu-radix64.h"
365118ebe8SLucas Mateus Castro (alqotel) 
375118ebe8SLucas Mateus Castro (alqotel) /* #define DUMP_PAGE_TABLES */
385118ebe8SLucas Mateus Castro (alqotel) 
39*306b5320SBALATON Zoltan /* Context used internally during MMU translations */
40*306b5320SBALATON Zoltan typedef struct {
41*306b5320SBALATON Zoltan     hwaddr raddr;      /* Real address             */
42*306b5320SBALATON Zoltan     hwaddr eaddr;      /* Effective address        */
43*306b5320SBALATON Zoltan     int prot;          /* Protection bits          */
44*306b5320SBALATON Zoltan     hwaddr hash[2];    /* Pagetable hash values    */
45*306b5320SBALATON Zoltan     target_ulong ptem; /* Virtual segment ID | API */
46*306b5320SBALATON Zoltan     int key;           /* Access key               */
47*306b5320SBALATON Zoltan     int nx;            /* Non-execute area         */
48*306b5320SBALATON Zoltan } mmu_ctx_t;
49*306b5320SBALATON Zoltan 
50d6ae8ec6SLucas Mateus Castro (alqotel) void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
51d6ae8ec6SLucas Mateus Castro (alqotel) {
52d6ae8ec6SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = env_archcpu(env);
53d6ae8ec6SLucas Mateus Castro (alqotel)     qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
54d6ae8ec6SLucas Mateus Castro (alqotel)     assert(!cpu->env.has_hv_mode || !cpu->vhyp);
55d6ae8ec6SLucas Mateus Castro (alqotel) #if defined(TARGET_PPC64)
56d6ae8ec6SLucas Mateus Castro (alqotel)     if (mmu_is_64bit(env->mmu_model)) {
57d6ae8ec6SLucas Mateus Castro (alqotel)         target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE;
58d6ae8ec6SLucas Mateus Castro (alqotel)         target_ulong htabsize = value & SDR_64_HTABSIZE;
59d6ae8ec6SLucas Mateus Castro (alqotel) 
60d6ae8ec6SLucas Mateus Castro (alqotel)         if (value & ~sdr_mask) {
61d6ae8ec6SLucas Mateus Castro (alqotel)             qemu_log_mask(LOG_GUEST_ERROR, "Invalid bits 0x"TARGET_FMT_lx
62d6ae8ec6SLucas Mateus Castro (alqotel)                      " set in SDR1", value & ~sdr_mask);
63d6ae8ec6SLucas Mateus Castro (alqotel)             value &= sdr_mask;
64d6ae8ec6SLucas Mateus Castro (alqotel)         }
65d6ae8ec6SLucas Mateus Castro (alqotel)         if (htabsize > 28) {
66d6ae8ec6SLucas Mateus Castro (alqotel)             qemu_log_mask(LOG_GUEST_ERROR, "Invalid HTABSIZE 0x" TARGET_FMT_lx
67d6ae8ec6SLucas Mateus Castro (alqotel)                      " stored in SDR1", htabsize);
68d6ae8ec6SLucas Mateus Castro (alqotel)             return;
69d6ae8ec6SLucas Mateus Castro (alqotel)         }
70d6ae8ec6SLucas Mateus Castro (alqotel)     }
71d6ae8ec6SLucas Mateus Castro (alqotel) #endif /* defined(TARGET_PPC64) */
72d6ae8ec6SLucas Mateus Castro (alqotel)     /* FIXME: Should check for valid HTABMASK values in 32-bit case */
73d6ae8ec6SLucas Mateus Castro (alqotel)     env->spr[SPR_SDR1] = value;
74d6ae8ec6SLucas Mateus Castro (alqotel) }
75d6ae8ec6SLucas Mateus Castro (alqotel) 
765118ebe8SLucas Mateus Castro (alqotel) /*****************************************************************************/
775118ebe8SLucas Mateus Castro (alqotel) /* PowerPC MMU emulation */
785118ebe8SLucas Mateus Castro (alqotel) 
795118ebe8SLucas Mateus Castro (alqotel) static int pp_check(int key, int pp, int nx)
805118ebe8SLucas Mateus Castro (alqotel) {
815118ebe8SLucas Mateus Castro (alqotel)     int access;
825118ebe8SLucas Mateus Castro (alqotel) 
835118ebe8SLucas Mateus Castro (alqotel)     /* Compute access rights */
845118ebe8SLucas Mateus Castro (alqotel)     access = 0;
855118ebe8SLucas Mateus Castro (alqotel)     if (key == 0) {
865118ebe8SLucas Mateus Castro (alqotel)         switch (pp) {
875118ebe8SLucas Mateus Castro (alqotel)         case 0x0:
885118ebe8SLucas Mateus Castro (alqotel)         case 0x1:
895118ebe8SLucas Mateus Castro (alqotel)         case 0x2:
905118ebe8SLucas Mateus Castro (alqotel)             access |= PAGE_WRITE;
915118ebe8SLucas Mateus Castro (alqotel)             /* fall through */
925118ebe8SLucas Mateus Castro (alqotel)         case 0x3:
935118ebe8SLucas Mateus Castro (alqotel)             access |= PAGE_READ;
945118ebe8SLucas Mateus Castro (alqotel)             break;
955118ebe8SLucas Mateus Castro (alqotel)         }
965118ebe8SLucas Mateus Castro (alqotel)     } else {
975118ebe8SLucas Mateus Castro (alqotel)         switch (pp) {
985118ebe8SLucas Mateus Castro (alqotel)         case 0x0:
995118ebe8SLucas Mateus Castro (alqotel)             access = 0;
1005118ebe8SLucas Mateus Castro (alqotel)             break;
1015118ebe8SLucas Mateus Castro (alqotel)         case 0x1:
1025118ebe8SLucas Mateus Castro (alqotel)         case 0x3:
1035118ebe8SLucas Mateus Castro (alqotel)             access = PAGE_READ;
1045118ebe8SLucas Mateus Castro (alqotel)             break;
1055118ebe8SLucas Mateus Castro (alqotel)         case 0x2:
1065118ebe8SLucas Mateus Castro (alqotel)             access = PAGE_READ | PAGE_WRITE;
1075118ebe8SLucas Mateus Castro (alqotel)             break;
1085118ebe8SLucas Mateus Castro (alqotel)         }
1095118ebe8SLucas Mateus Castro (alqotel)     }
1105118ebe8SLucas Mateus Castro (alqotel)     if (nx == 0) {
1115118ebe8SLucas Mateus Castro (alqotel)         access |= PAGE_EXEC;
1125118ebe8SLucas Mateus Castro (alqotel)     }
1135118ebe8SLucas Mateus Castro (alqotel) 
1145118ebe8SLucas Mateus Castro (alqotel)     return access;
1155118ebe8SLucas Mateus Castro (alqotel) }
1165118ebe8SLucas Mateus Castro (alqotel) 
1175118ebe8SLucas Mateus Castro (alqotel) static int check_prot(int prot, MMUAccessType access_type)
1185118ebe8SLucas Mateus Castro (alqotel) {
1195118ebe8SLucas Mateus Castro (alqotel)     return prot & prot_for_access_type(access_type) ? 0 : -2;
1205118ebe8SLucas Mateus Castro (alqotel) }
1215118ebe8SLucas Mateus Castro (alqotel) 
1225118ebe8SLucas Mateus Castro (alqotel) int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
1235118ebe8SLucas Mateus Castro (alqotel)                                     int way, int is_code)
1245118ebe8SLucas Mateus Castro (alqotel) {
1255118ebe8SLucas Mateus Castro (alqotel)     int nr;
1265118ebe8SLucas Mateus Castro (alqotel) 
1275118ebe8SLucas Mateus Castro (alqotel)     /* Select TLB num in a way from address */
1285118ebe8SLucas Mateus Castro (alqotel)     nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
1295118ebe8SLucas Mateus Castro (alqotel)     /* Select TLB way */
1305118ebe8SLucas Mateus Castro (alqotel)     nr += env->tlb_per_way * way;
1315118ebe8SLucas Mateus Castro (alqotel)     /* 6xx have separate TLBs for instructions and data */
1325118ebe8SLucas Mateus Castro (alqotel)     if (is_code && env->id_tlbs == 1) {
1335118ebe8SLucas Mateus Castro (alqotel)         nr += env->nb_tlb;
1345118ebe8SLucas Mateus Castro (alqotel)     }
1355118ebe8SLucas Mateus Castro (alqotel) 
1365118ebe8SLucas Mateus Castro (alqotel)     return nr;
1375118ebe8SLucas Mateus Castro (alqotel) }
1385118ebe8SLucas Mateus Castro (alqotel) 
1395118ebe8SLucas Mateus Castro (alqotel) static int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
1405118ebe8SLucas Mateus Castro (alqotel)                                 target_ulong pte1, int h,
1415118ebe8SLucas Mateus Castro (alqotel)                                 MMUAccessType access_type)
1425118ebe8SLucas Mateus Castro (alqotel) {
1435118ebe8SLucas Mateus Castro (alqotel)     target_ulong ptem, mmask;
1445118ebe8SLucas Mateus Castro (alqotel)     int access, ret, pteh, ptev, pp;
1455118ebe8SLucas Mateus Castro (alqotel) 
1465118ebe8SLucas Mateus Castro (alqotel)     ret = -1;
1475118ebe8SLucas Mateus Castro (alqotel)     /* Check validity and table match */
1485118ebe8SLucas Mateus Castro (alqotel)     ptev = pte_is_valid(pte0);
1495118ebe8SLucas Mateus Castro (alqotel)     pteh = (pte0 >> 6) & 1;
1505118ebe8SLucas Mateus Castro (alqotel)     if (ptev && h == pteh) {
1515118ebe8SLucas Mateus Castro (alqotel)         /* Check vsid & api */
1525118ebe8SLucas Mateus Castro (alqotel)         ptem = pte0 & PTE_PTEM_MASK;
1535118ebe8SLucas Mateus Castro (alqotel)         mmask = PTE_CHECK_MASK;
1545118ebe8SLucas Mateus Castro (alqotel)         pp = pte1 & 0x00000003;
1555118ebe8SLucas Mateus Castro (alqotel)         if (ptem == ctx->ptem) {
1565118ebe8SLucas Mateus Castro (alqotel)             if (ctx->raddr != (hwaddr)-1ULL) {
1575118ebe8SLucas Mateus Castro (alqotel)                 /* all matches should have equal RPN, WIMG & PP */
1585118ebe8SLucas Mateus Castro (alqotel)                 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
1595118ebe8SLucas Mateus Castro (alqotel)                     qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
1605118ebe8SLucas Mateus Castro (alqotel)                     return -3;
1615118ebe8SLucas Mateus Castro (alqotel)                 }
1625118ebe8SLucas Mateus Castro (alqotel)             }
1635118ebe8SLucas Mateus Castro (alqotel)             /* Compute access rights */
1645118ebe8SLucas Mateus Castro (alqotel)             access = pp_check(ctx->key, pp, ctx->nx);
1655118ebe8SLucas Mateus Castro (alqotel)             /* Keep the matching PTE information */
1665118ebe8SLucas Mateus Castro (alqotel)             ctx->raddr = pte1;
1675118ebe8SLucas Mateus Castro (alqotel)             ctx->prot = access;
1685118ebe8SLucas Mateus Castro (alqotel)             ret = check_prot(ctx->prot, access_type);
1695118ebe8SLucas Mateus Castro (alqotel)             if (ret == 0) {
1705118ebe8SLucas Mateus Castro (alqotel)                 /* Access granted */
1715118ebe8SLucas Mateus Castro (alqotel)                 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
1725118ebe8SLucas Mateus Castro (alqotel)             } else {
1735118ebe8SLucas Mateus Castro (alqotel)                 /* Access right violation */
1745118ebe8SLucas Mateus Castro (alqotel)                 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
1755118ebe8SLucas Mateus Castro (alqotel)             }
1765118ebe8SLucas Mateus Castro (alqotel)         }
1775118ebe8SLucas Mateus Castro (alqotel)     }
1785118ebe8SLucas Mateus Castro (alqotel) 
1795118ebe8SLucas Mateus Castro (alqotel)     return ret;
1805118ebe8SLucas Mateus Castro (alqotel) }
1815118ebe8SLucas Mateus Castro (alqotel) 
1825118ebe8SLucas Mateus Castro (alqotel) static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
1835118ebe8SLucas Mateus Castro (alqotel)                             int ret, MMUAccessType access_type)
1845118ebe8SLucas Mateus Castro (alqotel) {
1855118ebe8SLucas Mateus Castro (alqotel)     int store = 0;
1865118ebe8SLucas Mateus Castro (alqotel) 
1875118ebe8SLucas Mateus Castro (alqotel)     /* Update page flags */
1885118ebe8SLucas Mateus Castro (alqotel)     if (!(*pte1p & 0x00000100)) {
1895118ebe8SLucas Mateus Castro (alqotel)         /* Update accessed flag */
1905118ebe8SLucas Mateus Castro (alqotel)         *pte1p |= 0x00000100;
1915118ebe8SLucas Mateus Castro (alqotel)         store = 1;
1925118ebe8SLucas Mateus Castro (alqotel)     }
1935118ebe8SLucas Mateus Castro (alqotel)     if (!(*pte1p & 0x00000080)) {
1945118ebe8SLucas Mateus Castro (alqotel)         if (access_type == MMU_DATA_STORE && ret == 0) {
1955118ebe8SLucas Mateus Castro (alqotel)             /* Update changed flag */
1965118ebe8SLucas Mateus Castro (alqotel)             *pte1p |= 0x00000080;
1975118ebe8SLucas Mateus Castro (alqotel)             store = 1;
1985118ebe8SLucas Mateus Castro (alqotel)         } else {
1995118ebe8SLucas Mateus Castro (alqotel)             /* Force page fault for first write access */
2005118ebe8SLucas Mateus Castro (alqotel)             ctx->prot &= ~PAGE_WRITE;
2015118ebe8SLucas Mateus Castro (alqotel)         }
2025118ebe8SLucas Mateus Castro (alqotel)     }
2035118ebe8SLucas Mateus Castro (alqotel) 
2045118ebe8SLucas Mateus Castro (alqotel)     return store;
2055118ebe8SLucas Mateus Castro (alqotel) }
2065118ebe8SLucas Mateus Castro (alqotel) 
2075118ebe8SLucas Mateus Castro (alqotel) /* Software driven TLB helpers */
2085118ebe8SLucas Mateus Castro (alqotel) 
2095118ebe8SLucas Mateus Castro (alqotel) static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
2105118ebe8SLucas Mateus Castro (alqotel)                             target_ulong eaddr, MMUAccessType access_type)
2115118ebe8SLucas Mateus Castro (alqotel) {
2125118ebe8SLucas Mateus Castro (alqotel)     ppc6xx_tlb_t *tlb;
2135118ebe8SLucas Mateus Castro (alqotel)     int nr, best, way;
2145118ebe8SLucas Mateus Castro (alqotel)     int ret;
2155118ebe8SLucas Mateus Castro (alqotel) 
2165118ebe8SLucas Mateus Castro (alqotel)     best = -1;
2175118ebe8SLucas Mateus Castro (alqotel)     ret = -1; /* No TLB found */
2185118ebe8SLucas Mateus Castro (alqotel)     for (way = 0; way < env->nb_ways; way++) {
2195118ebe8SLucas Mateus Castro (alqotel)         nr = ppc6xx_tlb_getnum(env, eaddr, way, access_type == MMU_INST_FETCH);
2205118ebe8SLucas Mateus Castro (alqotel)         tlb = &env->tlb.tlb6[nr];
2215118ebe8SLucas Mateus Castro (alqotel)         /* This test "emulates" the PTE index match for hardware TLBs */
2225118ebe8SLucas Mateus Castro (alqotel)         if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
22356964585SCédric Le Goater             qemu_log_mask(CPU_LOG_MMU, "TLB %d/%d %s [" TARGET_FMT_lx
22456964585SCédric Le Goater                           " " TARGET_FMT_lx "] <> " TARGET_FMT_lx "\n",
22556964585SCédric Le Goater                           nr, env->nb_tlb,
2265118ebe8SLucas Mateus Castro (alqotel)                           pte_is_valid(tlb->pte0) ? "valid" : "inval",
2275118ebe8SLucas Mateus Castro (alqotel)                           tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
2285118ebe8SLucas Mateus Castro (alqotel)             continue;
2295118ebe8SLucas Mateus Castro (alqotel)         }
23056964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "TLB %d/%d %s " TARGET_FMT_lx " <> "
23156964585SCédric Le Goater                       TARGET_FMT_lx " " TARGET_FMT_lx " %c %c\n",
23256964585SCédric Le Goater                       nr, env->nb_tlb,
2335118ebe8SLucas Mateus Castro (alqotel)                       pte_is_valid(tlb->pte0) ? "valid" : "inval",
2345118ebe8SLucas Mateus Castro (alqotel)                       tlb->EPN, eaddr, tlb->pte1,
2355118ebe8SLucas Mateus Castro (alqotel)                       access_type == MMU_DATA_STORE ? 'S' : 'L',
2365118ebe8SLucas Mateus Castro (alqotel)                       access_type == MMU_INST_FETCH ? 'I' : 'D');
2375118ebe8SLucas Mateus Castro (alqotel)         switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1,
2385118ebe8SLucas Mateus Castro (alqotel)                                      0, access_type)) {
2395118ebe8SLucas Mateus Castro (alqotel)         case -2:
2405118ebe8SLucas Mateus Castro (alqotel)             /* Access violation */
2415118ebe8SLucas Mateus Castro (alqotel)             ret = -2;
2425118ebe8SLucas Mateus Castro (alqotel)             best = nr;
2435118ebe8SLucas Mateus Castro (alqotel)             break;
2440af20f35SBALATON Zoltan         case -1: /* No match */
2450af20f35SBALATON Zoltan         case -3: /* TLB inconsistency */
2465118ebe8SLucas Mateus Castro (alqotel)         default:
2475118ebe8SLucas Mateus Castro (alqotel)             break;
2485118ebe8SLucas Mateus Castro (alqotel)         case 0:
2495118ebe8SLucas Mateus Castro (alqotel)             /* access granted */
2505118ebe8SLucas Mateus Castro (alqotel)             /*
2515118ebe8SLucas Mateus Castro (alqotel)              * XXX: we should go on looping to check all TLBs
2525118ebe8SLucas Mateus Castro (alqotel)              *      consistency but we can speed-up the whole thing as
2535118ebe8SLucas Mateus Castro (alqotel)              *      the result would be undefined if TLBs are not
2545118ebe8SLucas Mateus Castro (alqotel)              *      consistent.
2555118ebe8SLucas Mateus Castro (alqotel)              */
2565118ebe8SLucas Mateus Castro (alqotel)             ret = 0;
2575118ebe8SLucas Mateus Castro (alqotel)             best = nr;
2585118ebe8SLucas Mateus Castro (alqotel)             goto done;
2595118ebe8SLucas Mateus Castro (alqotel)         }
2605118ebe8SLucas Mateus Castro (alqotel)     }
2615118ebe8SLucas Mateus Castro (alqotel)     if (best != -1) {
2625118ebe8SLucas Mateus Castro (alqotel) done:
263883f2c59SPhilippe Mathieu-Daudé         qemu_log_mask(CPU_LOG_MMU, "found TLB at addr " HWADDR_FMT_plx
26456964585SCédric Le Goater                       " prot=%01x ret=%d\n",
2655118ebe8SLucas Mateus Castro (alqotel)                       ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
2665118ebe8SLucas Mateus Castro (alqotel)         /* Update page flags */
2675118ebe8SLucas Mateus Castro (alqotel)         pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, access_type);
2685118ebe8SLucas Mateus Castro (alqotel)     }
2690af20f35SBALATON Zoltan #if defined(DUMP_PAGE_TABLES)
2700af20f35SBALATON Zoltan     if (qemu_loglevel_mask(CPU_LOG_MMU)) {
2710af20f35SBALATON Zoltan         CPUState *cs = env_cpu(env);
2720af20f35SBALATON Zoltan         hwaddr base = ppc_hash32_hpt_base(env_archcpu(env));
2730af20f35SBALATON Zoltan         hwaddr len = ppc_hash32_hpt_mask(env_archcpu(env)) + 0x80;
2740af20f35SBALATON Zoltan         uint32_t a0, a1, a2, a3;
2755118ebe8SLucas Mateus Castro (alqotel) 
2760af20f35SBALATON Zoltan         qemu_log("Page table: " HWADDR_FMT_plx " len " HWADDR_FMT_plx "\n",
2770af20f35SBALATON Zoltan                  base, len);
2780af20f35SBALATON Zoltan         for (hwaddr curaddr = base; curaddr < base + len; curaddr += 16) {
2790af20f35SBALATON Zoltan             a0 = ldl_phys(cs->as, curaddr);
2800af20f35SBALATON Zoltan             a1 = ldl_phys(cs->as, curaddr + 4);
2810af20f35SBALATON Zoltan             a2 = ldl_phys(cs->as, curaddr + 8);
2820af20f35SBALATON Zoltan             a3 = ldl_phys(cs->as, curaddr + 12);
2830af20f35SBALATON Zoltan             if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
2840af20f35SBALATON Zoltan                 qemu_log(HWADDR_FMT_plx ": %08x %08x %08x %08x\n",
2850af20f35SBALATON Zoltan                          curaddr, a0, a1, a2, a3);
2860af20f35SBALATON Zoltan             }
2870af20f35SBALATON Zoltan         }
2880af20f35SBALATON Zoltan     }
2890af20f35SBALATON Zoltan #endif
2905118ebe8SLucas Mateus Castro (alqotel)     return ret;
2915118ebe8SLucas Mateus Castro (alqotel) }
2925118ebe8SLucas Mateus Castro (alqotel) 
2935118ebe8SLucas Mateus Castro (alqotel) /* Perform BAT hit & translation */
2945118ebe8SLucas Mateus Castro (alqotel) static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
2955118ebe8SLucas Mateus Castro (alqotel)                                  int *validp, int *protp, target_ulong *BATu,
2965118ebe8SLucas Mateus Castro (alqotel)                                  target_ulong *BATl)
2975118ebe8SLucas Mateus Castro (alqotel) {
2985118ebe8SLucas Mateus Castro (alqotel)     target_ulong bl;
2995118ebe8SLucas Mateus Castro (alqotel)     int pp, valid, prot;
3005118ebe8SLucas Mateus Castro (alqotel) 
3015118ebe8SLucas Mateus Castro (alqotel)     bl = (*BATu & 0x00001FFC) << 15;
3025118ebe8SLucas Mateus Castro (alqotel)     valid = 0;
3035118ebe8SLucas Mateus Castro (alqotel)     prot = 0;
304d41ccf6eSVíctor Colombo     if ((!FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000002)) ||
305d41ccf6eSVíctor Colombo         (FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000001))) {
3065118ebe8SLucas Mateus Castro (alqotel)         valid = 1;
3075118ebe8SLucas Mateus Castro (alqotel)         pp = *BATl & 0x00000003;
3085118ebe8SLucas Mateus Castro (alqotel)         if (pp != 0) {
3095118ebe8SLucas Mateus Castro (alqotel)             prot = PAGE_READ | PAGE_EXEC;
3105118ebe8SLucas Mateus Castro (alqotel)             if (pp == 0x2) {
3115118ebe8SLucas Mateus Castro (alqotel)                 prot |= PAGE_WRITE;
3125118ebe8SLucas Mateus Castro (alqotel)             }
3135118ebe8SLucas Mateus Castro (alqotel)         }
3145118ebe8SLucas Mateus Castro (alqotel)     }
3155118ebe8SLucas Mateus Castro (alqotel)     *blp = bl;
3165118ebe8SLucas Mateus Castro (alqotel)     *validp = valid;
3175118ebe8SLucas Mateus Castro (alqotel)     *protp = prot;
3185118ebe8SLucas Mateus Castro (alqotel) }
3195118ebe8SLucas Mateus Castro (alqotel) 
3205118ebe8SLucas Mateus Castro (alqotel) static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
3215118ebe8SLucas Mateus Castro (alqotel)                            target_ulong virtual, MMUAccessType access_type)
3225118ebe8SLucas Mateus Castro (alqotel) {
3235118ebe8SLucas Mateus Castro (alqotel)     target_ulong *BATlt, *BATut, *BATu, *BATl;
3245118ebe8SLucas Mateus Castro (alqotel)     target_ulong BEPIl, BEPIu, bl;
3255118ebe8SLucas Mateus Castro (alqotel)     int i, valid, prot;
3265118ebe8SLucas Mateus Castro (alqotel)     int ret = -1;
3275118ebe8SLucas Mateus Castro (alqotel)     bool ifetch = access_type == MMU_INST_FETCH;
3285118ebe8SLucas Mateus Castro (alqotel) 
32956964585SCédric Le Goater     qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
3305118ebe8SLucas Mateus Castro (alqotel)                   ifetch ? 'I' : 'D', virtual);
3315118ebe8SLucas Mateus Castro (alqotel)     if (ifetch) {
3325118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->IBAT[1];
3335118ebe8SLucas Mateus Castro (alqotel)         BATut = env->IBAT[0];
3345118ebe8SLucas Mateus Castro (alqotel)     } else {
3355118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->DBAT[1];
3365118ebe8SLucas Mateus Castro (alqotel)         BATut = env->DBAT[0];
3375118ebe8SLucas Mateus Castro (alqotel)     }
3385118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_BATs; i++) {
3395118ebe8SLucas Mateus Castro (alqotel)         BATu = &BATut[i];
3405118ebe8SLucas Mateus Castro (alqotel)         BATl = &BATlt[i];
3415118ebe8SLucas Mateus Castro (alqotel)         BEPIu = *BATu & 0xF0000000;
3425118ebe8SLucas Mateus Castro (alqotel)         BEPIl = *BATu & 0x0FFE0000;
3435118ebe8SLucas Mateus Castro (alqotel)         bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
34456964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx " BATu "
34556964585SCédric Le Goater                       TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n", __func__,
3465118ebe8SLucas Mateus Castro (alqotel)                       ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl);
3475118ebe8SLucas Mateus Castro (alqotel)         if ((virtual & 0xF0000000) == BEPIu &&
3485118ebe8SLucas Mateus Castro (alqotel)             ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
3495118ebe8SLucas Mateus Castro (alqotel)             /* BAT matches */
3505118ebe8SLucas Mateus Castro (alqotel)             if (valid != 0) {
3515118ebe8SLucas Mateus Castro (alqotel)                 /* Get physical address */
3525118ebe8SLucas Mateus Castro (alqotel)                 ctx->raddr = (*BATl & 0xF0000000) |
3535118ebe8SLucas Mateus Castro (alqotel)                     ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
3545118ebe8SLucas Mateus Castro (alqotel)                     (virtual & 0x0001F000);
3555118ebe8SLucas Mateus Castro (alqotel)                 /* Compute access rights */
3565118ebe8SLucas Mateus Castro (alqotel)                 ctx->prot = prot;
3575118ebe8SLucas Mateus Castro (alqotel)                 ret = check_prot(ctx->prot, access_type);
3585118ebe8SLucas Mateus Castro (alqotel)                 if (ret == 0) {
359883f2c59SPhilippe Mathieu-Daudé                     qemu_log_mask(CPU_LOG_MMU, "BAT %d match: r " HWADDR_FMT_plx
36056964585SCédric Le Goater                                   " prot=%c%c\n", i, ctx->raddr,
36156964585SCédric Le Goater                                   ctx->prot & PAGE_READ ? 'R' : '-',
3625118ebe8SLucas Mateus Castro (alqotel)                                   ctx->prot & PAGE_WRITE ? 'W' : '-');
3635118ebe8SLucas Mateus Castro (alqotel)                 }
3645118ebe8SLucas Mateus Castro (alqotel)                 break;
3655118ebe8SLucas Mateus Castro (alqotel)             }
3665118ebe8SLucas Mateus Castro (alqotel)         }
3675118ebe8SLucas Mateus Castro (alqotel)     }
3685118ebe8SLucas Mateus Castro (alqotel)     if (ret < 0) {
3695118ebe8SLucas Mateus Castro (alqotel)         if (qemu_log_enabled()) {
37056964585SCédric Le Goater             qemu_log_mask(CPU_LOG_MMU, "no BAT match for "
37156964585SCédric Le Goater                           TARGET_FMT_lx ":\n", virtual);
3725118ebe8SLucas Mateus Castro (alqotel)             for (i = 0; i < 4; i++) {
3735118ebe8SLucas Mateus Castro (alqotel)                 BATu = &BATut[i];
3745118ebe8SLucas Mateus Castro (alqotel)                 BATl = &BATlt[i];
3755118ebe8SLucas Mateus Castro (alqotel)                 BEPIu = *BATu & 0xF0000000;
3765118ebe8SLucas Mateus Castro (alqotel)                 BEPIl = *BATu & 0x0FFE0000;
3775118ebe8SLucas Mateus Castro (alqotel)                 bl = (*BATu & 0x00001FFC) << 15;
37847bededcSBALATON Zoltan                 qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx
37947bededcSBALATON Zoltan                               " BATu " TARGET_FMT_lx " BATl " TARGET_FMT_lx
38047bededcSBALATON Zoltan                               "\n\t" TARGET_FMT_lx " " TARGET_FMT_lx " "
38147bededcSBALATON Zoltan                               TARGET_FMT_lx "\n", __func__, ifetch ? 'I' : 'D',
38247bededcSBALATON Zoltan                               i, virtual, *BATu, *BATl, BEPIu, BEPIl, bl);
3835118ebe8SLucas Mateus Castro (alqotel)             }
3845118ebe8SLucas Mateus Castro (alqotel)         }
3855118ebe8SLucas Mateus Castro (alqotel)     }
3865118ebe8SLucas Mateus Castro (alqotel)     /* No hit */
3875118ebe8SLucas Mateus Castro (alqotel)     return ret;
3885118ebe8SLucas Mateus Castro (alqotel) }
3895118ebe8SLucas Mateus Castro (alqotel) 
390269d6f00SBALATON Zoltan static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
391269d6f00SBALATON Zoltan                                        target_ulong eaddr,
392269d6f00SBALATON Zoltan                                        MMUAccessType access_type, int type)
3935118ebe8SLucas Mateus Castro (alqotel) {
3945118ebe8SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = env_archcpu(env);
3955118ebe8SLucas Mateus Castro (alqotel)     hwaddr hash;
396269d6f00SBALATON Zoltan     target_ulong vsid, sr, pgidx;
397d41ccf6eSVíctor Colombo     int ds, target_page_bits;
398d41ccf6eSVíctor Colombo     bool pr;
3995118ebe8SLucas Mateus Castro (alqotel) 
400269d6f00SBALATON Zoltan     /* First try to find a BAT entry if there are any */
401269d6f00SBALATON Zoltan     if (env->nb_BATs && get_bat_6xx_tlb(env, ctx, eaddr, access_type) == 0) {
402269d6f00SBALATON Zoltan         return 0;
403269d6f00SBALATON Zoltan     }
404269d6f00SBALATON Zoltan 
405269d6f00SBALATON Zoltan     /* Perform segment based translation when no BATs matched */
406d41ccf6eSVíctor Colombo     pr = FIELD_EX64(env->msr, MSR, PR);
4075118ebe8SLucas Mateus Castro (alqotel)     ctx->eaddr = eaddr;
4085118ebe8SLucas Mateus Castro (alqotel) 
4095118ebe8SLucas Mateus Castro (alqotel)     sr = env->sr[eaddr >> 28];
410d41ccf6eSVíctor Colombo     ctx->key = (((sr & 0x20000000) && pr) ||
411d41ccf6eSVíctor Colombo                 ((sr & 0x40000000) && !pr)) ? 1 : 0;
4125118ebe8SLucas Mateus Castro (alqotel)     ds = sr & 0x80000000 ? 1 : 0;
4135118ebe8SLucas Mateus Castro (alqotel)     ctx->nx = sr & 0x10000000 ? 1 : 0;
4145118ebe8SLucas Mateus Castro (alqotel)     vsid = sr & 0x00FFFFFF;
4155118ebe8SLucas Mateus Castro (alqotel)     target_page_bits = TARGET_PAGE_BITS;
4165118ebe8SLucas Mateus Castro (alqotel)     qemu_log_mask(CPU_LOG_MMU,
4175118ebe8SLucas Mateus Castro (alqotel)                   "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
4185118ebe8SLucas Mateus Castro (alqotel)                   " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
4195118ebe8SLucas Mateus Castro (alqotel)                   " ir=%d dr=%d pr=%d %d t=%d\n",
420d41ccf6eSVíctor Colombo                   eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr,
421e4eea6efSVíctor Colombo                   (int)FIELD_EX64(env->msr, MSR, IR),
422e4eea6efSVíctor Colombo                   (int)FIELD_EX64(env->msr, MSR, DR), pr ? 1 : 0,
42356964585SCédric Le Goater                   access_type == MMU_DATA_STORE, type);
4245118ebe8SLucas Mateus Castro (alqotel)     pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
4255118ebe8SLucas Mateus Castro (alqotel)     hash = vsid ^ pgidx;
4265118ebe8SLucas Mateus Castro (alqotel)     ctx->ptem = (vsid << 7) | (pgidx >> 10);
4275118ebe8SLucas Mateus Castro (alqotel) 
42847bededcSBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "pte segment: key=%d ds %d nx %d vsid "
42947bededcSBALATON Zoltan                   TARGET_FMT_lx "\n", ctx->key, ds, ctx->nx, vsid);
4305118ebe8SLucas Mateus Castro (alqotel)     if (!ds) {
4315118ebe8SLucas Mateus Castro (alqotel)         /* Check if instruction fetch is allowed, if needed */
432f1418bdeSBALATON Zoltan         if (type == ACCESS_CODE && ctx->nx) {
433f1418bdeSBALATON Zoltan             qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
434f1418bdeSBALATON Zoltan             return -3;
435f1418bdeSBALATON Zoltan         }
4365118ebe8SLucas Mateus Castro (alqotel)         /* Page address translation */
437f1418bdeSBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx " htab_mask "
438f1418bdeSBALATON Zoltan                       HWADDR_FMT_plx " hash " HWADDR_FMT_plx "\n",
4395118ebe8SLucas Mateus Castro (alqotel)                       ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
4405118ebe8SLucas Mateus Castro (alqotel)         ctx->hash[0] = hash;
4415118ebe8SLucas Mateus Castro (alqotel)         ctx->hash[1] = ~hash;
4425118ebe8SLucas Mateus Castro (alqotel) 
4435118ebe8SLucas Mateus Castro (alqotel)         /* Initialize real address with an invalid value */
4445118ebe8SLucas Mateus Castro (alqotel)         ctx->raddr = (hwaddr)-1ULL;
4455118ebe8SLucas Mateus Castro (alqotel)         /* Software TLB search */
446f3f66a31SBALATON Zoltan         return ppc6xx_tlb_check(env, ctx, eaddr, access_type);
447f3f66a31SBALATON Zoltan     }
4485118ebe8SLucas Mateus Castro (alqotel) 
449f3f66a31SBALATON Zoltan     /* Direct-store segment : absolutely *BUGGY* for now */
450f3f66a31SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
4515118ebe8SLucas Mateus Castro (alqotel)     switch (type) {
4525118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_INT:
4535118ebe8SLucas Mateus Castro (alqotel)         /* Integer load/store : only access allowed */
4545118ebe8SLucas Mateus Castro (alqotel)         break;
4555118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_CODE:
4565118ebe8SLucas Mateus Castro (alqotel)         /* No code fetch is allowed in direct-store areas */
4575118ebe8SLucas Mateus Castro (alqotel)         return -4;
4585118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_FLOAT:
4595118ebe8SLucas Mateus Castro (alqotel)         /* Floating point load/store */
4605118ebe8SLucas Mateus Castro (alqotel)         return -4;
4615118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_RES:
4625118ebe8SLucas Mateus Castro (alqotel)         /* lwarx, ldarx or srwcx. */
4635118ebe8SLucas Mateus Castro (alqotel)         return -4;
4645118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_CACHE:
4655118ebe8SLucas Mateus Castro (alqotel)         /*
4665118ebe8SLucas Mateus Castro (alqotel)          * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
4675118ebe8SLucas Mateus Castro (alqotel)          *
4685118ebe8SLucas Mateus Castro (alqotel)          * Should make the instruction do no-op.  As it already do
4695118ebe8SLucas Mateus Castro (alqotel)          * no-op, it's quite easy :-)
4705118ebe8SLucas Mateus Castro (alqotel)          */
4715118ebe8SLucas Mateus Castro (alqotel)         ctx->raddr = eaddr;
4725118ebe8SLucas Mateus Castro (alqotel)         return 0;
4735118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_EXT:
4745118ebe8SLucas Mateus Castro (alqotel)         /* eciwx or ecowx */
4755118ebe8SLucas Mateus Castro (alqotel)         return -4;
4765118ebe8SLucas Mateus Castro (alqotel)     default:
477f3f66a31SBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need address"
478f3f66a31SBALATON Zoltan                                    " translation\n");
4795118ebe8SLucas Mateus Castro (alqotel)         return -4;
4805118ebe8SLucas Mateus Castro (alqotel)     }
4815118ebe8SLucas Mateus Castro (alqotel)     if ((access_type == MMU_DATA_STORE || ctx->key != 1) &&
4825118ebe8SLucas Mateus Castro (alqotel)         (access_type == MMU_DATA_LOAD || ctx->key != 0)) {
4835118ebe8SLucas Mateus Castro (alqotel)         ctx->raddr = eaddr;
484f3f66a31SBALATON Zoltan         return 2;
4855118ebe8SLucas Mateus Castro (alqotel)     }
486f3f66a31SBALATON Zoltan     return -2;
4875118ebe8SLucas Mateus Castro (alqotel) }
4885118ebe8SLucas Mateus Castro (alqotel) 
4895118ebe8SLucas Mateus Castro (alqotel) /* Generic TLB check function for embedded PowerPC implementations */
4902b23daa8SBALATON Zoltan static bool ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
4915118ebe8SLucas Mateus Castro (alqotel)                              hwaddr *raddrp,
49262860c5fSBALATON Zoltan                              target_ulong address, uint32_t pid, int i)
4935118ebe8SLucas Mateus Castro (alqotel) {
4945118ebe8SLucas Mateus Castro (alqotel)     target_ulong mask;
4955118ebe8SLucas Mateus Castro (alqotel) 
4965118ebe8SLucas Mateus Castro (alqotel)     /* Check valid flag */
4975118ebe8SLucas Mateus Castro (alqotel)     if (!(tlb->prot & PAGE_VALID)) {
4982b23daa8SBALATON Zoltan         return false;
4995118ebe8SLucas Mateus Castro (alqotel)     }
5005118ebe8SLucas Mateus Castro (alqotel)     mask = ~(tlb->size - 1);
50156964585SCédric Le Goater     qemu_log_mask(CPU_LOG_MMU, "%s: TLB %d address " TARGET_FMT_lx
50256964585SCédric Le Goater                   " PID %u <=> " TARGET_FMT_lx " " TARGET_FMT_lx " %u %x\n",
50356964585SCédric Le Goater                   __func__, i, address, pid, tlb->EPN,
5045118ebe8SLucas Mateus Castro (alqotel)                   mask, (uint32_t)tlb->PID, tlb->prot);
5055118ebe8SLucas Mateus Castro (alqotel)     /* Check PID */
5065118ebe8SLucas Mateus Castro (alqotel)     if (tlb->PID != 0 && tlb->PID != pid) {
5072b23daa8SBALATON Zoltan         return false;
5085118ebe8SLucas Mateus Castro (alqotel)     }
5095118ebe8SLucas Mateus Castro (alqotel)     /* Check effective address */
5105118ebe8SLucas Mateus Castro (alqotel)     if ((address & mask) != tlb->EPN) {
5112b23daa8SBALATON Zoltan         return false;
5125118ebe8SLucas Mateus Castro (alqotel)     }
5135118ebe8SLucas Mateus Castro (alqotel)     *raddrp = (tlb->RPN & mask) | (address & ~mask);
5142b23daa8SBALATON Zoltan     return true;
5155118ebe8SLucas Mateus Castro (alqotel) }
5165118ebe8SLucas Mateus Castro (alqotel) 
517753441c8SBALATON Zoltan /* Generic TLB search function for PowerPC embedded implementations */
518753441c8SBALATON Zoltan int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid)
519753441c8SBALATON Zoltan {
520753441c8SBALATON Zoltan     ppcemb_tlb_t *tlb;
521753441c8SBALATON Zoltan     hwaddr raddr;
522bb60364cSBALATON Zoltan     int i;
523753441c8SBALATON Zoltan 
524753441c8SBALATON Zoltan     for (i = 0; i < env->nb_tlb; i++) {
525753441c8SBALATON Zoltan         tlb = &env->tlb.tlbe[i];
5262b23daa8SBALATON Zoltan         if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, i)) {
527bb60364cSBALATON Zoltan             return i;
528753441c8SBALATON Zoltan         }
529753441c8SBALATON Zoltan     }
530bb60364cSBALATON Zoltan     return -1;
531753441c8SBALATON Zoltan }
532753441c8SBALATON Zoltan 
5335cc867a6SBALATON Zoltan static int mmu40x_get_physical_address(CPUPPCState *env, hwaddr *raddr,
5345cc867a6SBALATON Zoltan                                        int *prot, target_ulong address,
5355118ebe8SLucas Mateus Castro (alqotel)                                        MMUAccessType access_type)
5365118ebe8SLucas Mateus Castro (alqotel) {
5375118ebe8SLucas Mateus Castro (alqotel)     ppcemb_tlb_t *tlb;
5385118ebe8SLucas Mateus Castro (alqotel)     int i, ret, zsel, zpr, pr;
5395118ebe8SLucas Mateus Castro (alqotel) 
5405118ebe8SLucas Mateus Castro (alqotel)     ret = -1;
541d41ccf6eSVíctor Colombo     pr = FIELD_EX64(env->msr, MSR, PR);
5425118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_tlb; i++) {
5435118ebe8SLucas Mateus Castro (alqotel)         tlb = &env->tlb.tlbe[i];
5445cc867a6SBALATON Zoltan         if (!ppcemb_tlb_check(env, tlb, raddr, address,
5452b23daa8SBALATON Zoltan                               env->spr[SPR_40x_PID], i)) {
5465118ebe8SLucas Mateus Castro (alqotel)             continue;
5475118ebe8SLucas Mateus Castro (alqotel)         }
5485118ebe8SLucas Mateus Castro (alqotel)         zsel = (tlb->attr >> 4) & 0xF;
5495118ebe8SLucas Mateus Castro (alqotel)         zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
55056964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU,
55156964585SCédric Le Goater                       "%s: TLB %d zsel %d zpr %d ty %d attr %08x\n",
5525118ebe8SLucas Mateus Castro (alqotel)                       __func__, i, zsel, zpr, access_type, tlb->attr);
5535118ebe8SLucas Mateus Castro (alqotel)         /* Check execute enable bit */
5545118ebe8SLucas Mateus Castro (alqotel)         switch (zpr) {
5555118ebe8SLucas Mateus Castro (alqotel)         case 0x2:
5565118ebe8SLucas Mateus Castro (alqotel)             if (pr != 0) {
5575118ebe8SLucas Mateus Castro (alqotel)                 goto check_perms;
5585118ebe8SLucas Mateus Castro (alqotel)             }
5595118ebe8SLucas Mateus Castro (alqotel)             /* fall through */
5605118ebe8SLucas Mateus Castro (alqotel)         case 0x3:
5615118ebe8SLucas Mateus Castro (alqotel)             /* All accesses granted */
5625cc867a6SBALATON Zoltan             *prot = PAGE_RWX;
5635118ebe8SLucas Mateus Castro (alqotel)             ret = 0;
5645118ebe8SLucas Mateus Castro (alqotel)             break;
5655cc867a6SBALATON Zoltan 
5665118ebe8SLucas Mateus Castro (alqotel)         case 0x0:
5675118ebe8SLucas Mateus Castro (alqotel)             if (pr != 0) {
5685118ebe8SLucas Mateus Castro (alqotel)                 /* Raise Zone protection fault.  */
5695118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_40x_ESR] = 1 << 22;
5705cc867a6SBALATON Zoltan                 *prot = 0;
5715118ebe8SLucas Mateus Castro (alqotel)                 ret = -2;
5725118ebe8SLucas Mateus Castro (alqotel)                 break;
5735118ebe8SLucas Mateus Castro (alqotel)             }
5745118ebe8SLucas Mateus Castro (alqotel)             /* fall through */
5755118ebe8SLucas Mateus Castro (alqotel)         case 0x1:
5765118ebe8SLucas Mateus Castro (alqotel) check_perms:
5775118ebe8SLucas Mateus Castro (alqotel)             /* Check from TLB entry */
5785cc867a6SBALATON Zoltan             *prot = tlb->prot;
5795cc867a6SBALATON Zoltan             ret = check_prot(*prot, access_type);
5805118ebe8SLucas Mateus Castro (alqotel)             if (ret == -2) {
5815118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_40x_ESR] = 0;
5825118ebe8SLucas Mateus Castro (alqotel)             }
5835118ebe8SLucas Mateus Castro (alqotel)             break;
5845118ebe8SLucas Mateus Castro (alqotel)         }
5855118ebe8SLucas Mateus Castro (alqotel)     }
5865cc867a6SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => "
5875cc867a6SBALATON Zoltan                   HWADDR_FMT_plx " %d %d\n",  __func__,
5885cc867a6SBALATON Zoltan                   ret < 0 ? "refused" : "granted", address,
5895cc867a6SBALATON Zoltan                   ret < 0 ? 0 : *raddr, *prot, ret);
5905118ebe8SLucas Mateus Castro (alqotel) 
5915118ebe8SLucas Mateus Castro (alqotel)     return ret;
5925118ebe8SLucas Mateus Castro (alqotel) }
5935118ebe8SLucas Mateus Castro (alqotel) 
594a5436bc6SBALATON Zoltan static bool mmubooke_check_pid(CPUPPCState *env, ppcemb_tlb_t *tlb,
595a5436bc6SBALATON Zoltan                                hwaddr *raddr, target_ulong addr, int i)
596a5436bc6SBALATON Zoltan {
597a5436bc6SBALATON Zoltan     if (ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID], i)) {
598a5436bc6SBALATON Zoltan         if (!env->nb_pids) {
599a5436bc6SBALATON Zoltan             /* Extend the physical address to 36 bits */
600a5436bc6SBALATON Zoltan             *raddr |= (uint64_t)(tlb->RPN & 0xF) << 32;
601a5436bc6SBALATON Zoltan         }
602a5436bc6SBALATON Zoltan         return true;
603a5436bc6SBALATON Zoltan     } else if (!env->nb_pids) {
604a5436bc6SBALATON Zoltan         return false;
605a5436bc6SBALATON Zoltan     }
606a5436bc6SBALATON Zoltan     if (env->spr[SPR_BOOKE_PID1] &&
607a5436bc6SBALATON Zoltan         ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID1], i)) {
608a5436bc6SBALATON Zoltan         return true;
609a5436bc6SBALATON Zoltan     }
610a5436bc6SBALATON Zoltan     if (env->spr[SPR_BOOKE_PID2] &&
611a5436bc6SBALATON Zoltan         ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID2], i)) {
612a5436bc6SBALATON Zoltan         return true;
613a5436bc6SBALATON Zoltan     }
614a5436bc6SBALATON Zoltan     return false;
615a5436bc6SBALATON Zoltan }
616a5436bc6SBALATON Zoltan 
6175118ebe8SLucas Mateus Castro (alqotel) static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
6185118ebe8SLucas Mateus Castro (alqotel)                               hwaddr *raddr, int *prot, target_ulong address,
6195118ebe8SLucas Mateus Castro (alqotel)                               MMUAccessType access_type, int i)
6205118ebe8SLucas Mateus Castro (alqotel) {
621a5436bc6SBALATON Zoltan     if (!mmubooke_check_pid(env, tlb, raddr, address, i)) {
62256964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: TLB entry not found\n", __func__);
6235118ebe8SLucas Mateus Castro (alqotel)         return -1;
624a5436bc6SBALATON Zoltan     }
6255118ebe8SLucas Mateus Castro (alqotel) 
6265118ebe8SLucas Mateus Castro (alqotel)     /* Check the address space */
6274d979c9fSVíctor Colombo     if ((access_type == MMU_INST_FETCH ?
628e4eea6efSVíctor Colombo         FIELD_EX64(env->msr, MSR, IR) :
629e4eea6efSVíctor Colombo         FIELD_EX64(env->msr, MSR, DR)) != (tlb->attr & 1)) {
63056964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
6315118ebe8SLucas Mateus Castro (alqotel)         return -1;
6325118ebe8SLucas Mateus Castro (alqotel)     }
6335118ebe8SLucas Mateus Castro (alqotel) 
6343f520078SBALATON Zoltan     if (FIELD_EX64(env->msr, MSR, PR)) {
635750fbe33SBALATON Zoltan         *prot = tlb->prot & 0xF;
6363f520078SBALATON Zoltan     } else {
637750fbe33SBALATON Zoltan         *prot = (tlb->prot >> 4) & 0xF;
6383f520078SBALATON Zoltan     }
639750fbe33SBALATON Zoltan     if (*prot & prot_for_access_type(access_type)) {
64056964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
6415118ebe8SLucas Mateus Castro (alqotel)         return 0;
6425118ebe8SLucas Mateus Castro (alqotel)     }
6435118ebe8SLucas Mateus Castro (alqotel) 
644750fbe33SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot);
6455118ebe8SLucas Mateus Castro (alqotel)     return access_type == MMU_INST_FETCH ? -3 : -2;
6465118ebe8SLucas Mateus Castro (alqotel) }
6475118ebe8SLucas Mateus Castro (alqotel) 
648ecff3394SBALATON Zoltan static int mmubooke_get_physical_address(CPUPPCState *env, hwaddr *raddr,
649ecff3394SBALATON Zoltan                                          int *prot, target_ulong address,
6505118ebe8SLucas Mateus Castro (alqotel)                                          MMUAccessType access_type)
6515118ebe8SLucas Mateus Castro (alqotel) {
6525118ebe8SLucas Mateus Castro (alqotel)     ppcemb_tlb_t *tlb;
653ecff3394SBALATON Zoltan     int i, ret = -1;
6545118ebe8SLucas Mateus Castro (alqotel) 
6555118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_tlb; i++) {
6565118ebe8SLucas Mateus Castro (alqotel)         tlb = &env->tlb.tlbe[i];
657ecff3394SBALATON Zoltan         ret = mmubooke_check_tlb(env, tlb, raddr, prot, address,
6585118ebe8SLucas Mateus Castro (alqotel)                                  access_type, i);
6595118ebe8SLucas Mateus Castro (alqotel)         if (ret != -1) {
6605118ebe8SLucas Mateus Castro (alqotel)             break;
6615118ebe8SLucas Mateus Castro (alqotel)         }
6625118ebe8SLucas Mateus Castro (alqotel)     }
663ecff3394SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU,
664ecff3394SBALATON Zoltan                   "%s: access %s " TARGET_FMT_lx " => " HWADDR_FMT_plx
665ecff3394SBALATON Zoltan                   " %d %d\n", __func__, ret < 0 ? "refused" : "granted",
666ecff3394SBALATON Zoltan                   address, ret < 0 ? -1 : *raddr, ret == -1 ? 0 : *prot, ret);
6675118ebe8SLucas Mateus Castro (alqotel)     return ret;
6685118ebe8SLucas Mateus Castro (alqotel) }
6695118ebe8SLucas Mateus Castro (alqotel) 
670a1fa47faSBALATON Zoltan hwaddr booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb)
6715118ebe8SLucas Mateus Castro (alqotel) {
6725118ebe8SLucas Mateus Castro (alqotel)     int tlbm_size;
6735118ebe8SLucas Mateus Castro (alqotel) 
6745118ebe8SLucas Mateus Castro (alqotel)     tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
6755118ebe8SLucas Mateus Castro (alqotel) 
6765118ebe8SLucas Mateus Castro (alqotel)     return 1024ULL << tlbm_size;
6775118ebe8SLucas Mateus Castro (alqotel) }
6785118ebe8SLucas Mateus Castro (alqotel) 
6795118ebe8SLucas Mateus Castro (alqotel) /* TLB check function for MAS based SoftTLBs */
680a1fa47faSBALATON Zoltan int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddrp,
681a1fa47faSBALATON Zoltan                      target_ulong address, uint32_t pid)
6825118ebe8SLucas Mateus Castro (alqotel) {
6835118ebe8SLucas Mateus Castro (alqotel)     hwaddr mask;
6845118ebe8SLucas Mateus Castro (alqotel)     uint32_t tlb_pid;
6855118ebe8SLucas Mateus Castro (alqotel) 
686cda23360SVíctor Colombo     if (!FIELD_EX64(env->msr, MSR, CM)) {
6875118ebe8SLucas Mateus Castro (alqotel)         /* In 32bit mode we can only address 32bit EAs */
6885118ebe8SLucas Mateus Castro (alqotel)         address = (uint32_t)address;
6895118ebe8SLucas Mateus Castro (alqotel)     }
6905118ebe8SLucas Mateus Castro (alqotel) 
6915118ebe8SLucas Mateus Castro (alqotel)     /* Check valid flag */
6925118ebe8SLucas Mateus Castro (alqotel)     if (!(tlb->mas1 & MAS1_VALID)) {
6935118ebe8SLucas Mateus Castro (alqotel)         return -1;
6945118ebe8SLucas Mateus Castro (alqotel)     }
6955118ebe8SLucas Mateus Castro (alqotel) 
6965118ebe8SLucas Mateus Castro (alqotel)     mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
69756964585SCédric Le Goater     qemu_log_mask(CPU_LOG_MMU, "%s: TLB ADDR=0x" TARGET_FMT_lx
69856964585SCédric Le Goater                   " PID=0x%x MAS1=0x%x MAS2=0x%" PRIx64 " mask=0x%"
69956964585SCédric Le Goater                   HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%" PRIx32 "\n",
70056964585SCédric Le Goater                   __func__, address, pid, tlb->mas1, tlb->mas2, mask,
7015118ebe8SLucas Mateus Castro (alqotel)                   tlb->mas7_3, tlb->mas8);
7025118ebe8SLucas Mateus Castro (alqotel) 
7035118ebe8SLucas Mateus Castro (alqotel)     /* Check PID */
7045118ebe8SLucas Mateus Castro (alqotel)     tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
7055118ebe8SLucas Mateus Castro (alqotel)     if (tlb_pid != 0 && tlb_pid != pid) {
7065118ebe8SLucas Mateus Castro (alqotel)         return -1;
7075118ebe8SLucas Mateus Castro (alqotel)     }
7085118ebe8SLucas Mateus Castro (alqotel) 
7095118ebe8SLucas Mateus Castro (alqotel)     /* Check effective address */
7105118ebe8SLucas Mateus Castro (alqotel)     if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
7115118ebe8SLucas Mateus Castro (alqotel)         return -1;
7125118ebe8SLucas Mateus Castro (alqotel)     }
7135118ebe8SLucas Mateus Castro (alqotel) 
7145118ebe8SLucas Mateus Castro (alqotel)     if (raddrp) {
7155118ebe8SLucas Mateus Castro (alqotel)         *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
7165118ebe8SLucas Mateus Castro (alqotel)     }
7175118ebe8SLucas Mateus Castro (alqotel) 
7185118ebe8SLucas Mateus Castro (alqotel)     return 0;
7195118ebe8SLucas Mateus Castro (alqotel) }
7205118ebe8SLucas Mateus Castro (alqotel) 
7215118ebe8SLucas Mateus Castro (alqotel) static bool is_epid_mmu(int mmu_idx)
7225118ebe8SLucas Mateus Castro (alqotel) {
7235118ebe8SLucas Mateus Castro (alqotel)     return mmu_idx == PPC_TLB_EPID_STORE || mmu_idx == PPC_TLB_EPID_LOAD;
7245118ebe8SLucas Mateus Castro (alqotel) }
7255118ebe8SLucas Mateus Castro (alqotel) 
7265118ebe8SLucas Mateus Castro (alqotel) static uint32_t mmubooke206_esr(int mmu_idx, MMUAccessType access_type)
7275118ebe8SLucas Mateus Castro (alqotel) {
7285118ebe8SLucas Mateus Castro (alqotel)     uint32_t esr = 0;
7295118ebe8SLucas Mateus Castro (alqotel)     if (access_type == MMU_DATA_STORE) {
7305118ebe8SLucas Mateus Castro (alqotel)         esr |= ESR_ST;
7315118ebe8SLucas Mateus Castro (alqotel)     }
7325118ebe8SLucas Mateus Castro (alqotel)     if (is_epid_mmu(mmu_idx)) {
7335118ebe8SLucas Mateus Castro (alqotel)         esr |= ESR_EPID;
7345118ebe8SLucas Mateus Castro (alqotel)     }
7355118ebe8SLucas Mateus Castro (alqotel)     return esr;
7365118ebe8SLucas Mateus Castro (alqotel) }
7375118ebe8SLucas Mateus Castro (alqotel) 
7385118ebe8SLucas Mateus Castro (alqotel) /*
7395118ebe8SLucas Mateus Castro (alqotel)  * Get EPID register given the mmu_idx. If this is regular load,
7405118ebe8SLucas Mateus Castro (alqotel)  * construct the EPID access bits from current processor state
7415118ebe8SLucas Mateus Castro (alqotel)  *
7425118ebe8SLucas Mateus Castro (alqotel)  * Get the effective AS and PR bits and the PID. The PID is returned
7435118ebe8SLucas Mateus Castro (alqotel)  * only if EPID load is requested, otherwise the caller must detect
7445118ebe8SLucas Mateus Castro (alqotel)  * the correct EPID.  Return true if valid EPID is returned.
7455118ebe8SLucas Mateus Castro (alqotel)  */
7465118ebe8SLucas Mateus Castro (alqotel) static bool mmubooke206_get_as(CPUPPCState *env,
7475118ebe8SLucas Mateus Castro (alqotel)                                int mmu_idx, uint32_t *epid_out,
7485118ebe8SLucas Mateus Castro (alqotel)                                bool *as_out, bool *pr_out)
7495118ebe8SLucas Mateus Castro (alqotel) {
7505118ebe8SLucas Mateus Castro (alqotel)     if (is_epid_mmu(mmu_idx)) {
7515118ebe8SLucas Mateus Castro (alqotel)         uint32_t epidr;
7525118ebe8SLucas Mateus Castro (alqotel)         if (mmu_idx == PPC_TLB_EPID_STORE) {
7535118ebe8SLucas Mateus Castro (alqotel)             epidr = env->spr[SPR_BOOKE_EPSC];
7545118ebe8SLucas Mateus Castro (alqotel)         } else {
7555118ebe8SLucas Mateus Castro (alqotel)             epidr = env->spr[SPR_BOOKE_EPLC];
7565118ebe8SLucas Mateus Castro (alqotel)         }
7575118ebe8SLucas Mateus Castro (alqotel)         *epid_out = (epidr & EPID_EPID) >> EPID_EPID_SHIFT;
7585118ebe8SLucas Mateus Castro (alqotel)         *as_out = !!(epidr & EPID_EAS);
7595118ebe8SLucas Mateus Castro (alqotel)         *pr_out = !!(epidr & EPID_EPR);
7605118ebe8SLucas Mateus Castro (alqotel)         return true;
7615118ebe8SLucas Mateus Castro (alqotel)     } else {
76226363616SVíctor Colombo         *as_out = FIELD_EX64(env->msr, MSR, DS);
763d41ccf6eSVíctor Colombo         *pr_out = FIELD_EX64(env->msr, MSR, PR);
7645118ebe8SLucas Mateus Castro (alqotel)         return false;
7655118ebe8SLucas Mateus Castro (alqotel)     }
7665118ebe8SLucas Mateus Castro (alqotel) }
7675118ebe8SLucas Mateus Castro (alqotel) 
7685118ebe8SLucas Mateus Castro (alqotel) /* Check if the tlb found by hashing really matches */
7695118ebe8SLucas Mateus Castro (alqotel) static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
7705118ebe8SLucas Mateus Castro (alqotel)                                  hwaddr *raddr, int *prot,
7715118ebe8SLucas Mateus Castro (alqotel)                                  target_ulong address,
7725118ebe8SLucas Mateus Castro (alqotel)                                  MMUAccessType access_type, int mmu_idx)
7735118ebe8SLucas Mateus Castro (alqotel) {
7745118ebe8SLucas Mateus Castro (alqotel)     uint32_t epid;
7755118ebe8SLucas Mateus Castro (alqotel)     bool as, pr;
7765118ebe8SLucas Mateus Castro (alqotel)     bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
7775118ebe8SLucas Mateus Castro (alqotel) 
7785118ebe8SLucas Mateus Castro (alqotel)     if (!use_epid) {
7795118ebe8SLucas Mateus Castro (alqotel)         if (ppcmas_tlb_check(env, tlb, raddr, address,
7805118ebe8SLucas Mateus Castro (alqotel)                              env->spr[SPR_BOOKE_PID]) >= 0) {
7815118ebe8SLucas Mateus Castro (alqotel)             goto found_tlb;
7825118ebe8SLucas Mateus Castro (alqotel)         }
7835118ebe8SLucas Mateus Castro (alqotel) 
7845118ebe8SLucas Mateus Castro (alqotel)         if (env->spr[SPR_BOOKE_PID1] &&
7855118ebe8SLucas Mateus Castro (alqotel)             ppcmas_tlb_check(env, tlb, raddr, address,
7865118ebe8SLucas Mateus Castro (alqotel)                              env->spr[SPR_BOOKE_PID1]) >= 0) {
7875118ebe8SLucas Mateus Castro (alqotel)             goto found_tlb;
7885118ebe8SLucas Mateus Castro (alqotel)         }
7895118ebe8SLucas Mateus Castro (alqotel) 
7905118ebe8SLucas Mateus Castro (alqotel)         if (env->spr[SPR_BOOKE_PID2] &&
7915118ebe8SLucas Mateus Castro (alqotel)             ppcmas_tlb_check(env, tlb, raddr, address,
7925118ebe8SLucas Mateus Castro (alqotel)                              env->spr[SPR_BOOKE_PID2]) >= 0) {
7935118ebe8SLucas Mateus Castro (alqotel)             goto found_tlb;
7945118ebe8SLucas Mateus Castro (alqotel)         }
7955118ebe8SLucas Mateus Castro (alqotel)     } else {
7965118ebe8SLucas Mateus Castro (alqotel)         if (ppcmas_tlb_check(env, tlb, raddr, address, epid) >= 0) {
7975118ebe8SLucas Mateus Castro (alqotel)             goto found_tlb;
7985118ebe8SLucas Mateus Castro (alqotel)         }
7995118ebe8SLucas Mateus Castro (alqotel)     }
8005118ebe8SLucas Mateus Castro (alqotel) 
801e4cadfbeSBernhard Beschow     qemu_log_mask(CPU_LOG_MMU, "%s: No TLB entry found for effective address "
802e4cadfbeSBernhard Beschow                   "0x" TARGET_FMT_lx "\n", __func__, address);
8035118ebe8SLucas Mateus Castro (alqotel)     return -1;
8045118ebe8SLucas Mateus Castro (alqotel) 
8055118ebe8SLucas Mateus Castro (alqotel) found_tlb:
8065118ebe8SLucas Mateus Castro (alqotel) 
8073f520078SBALATON Zoltan     /* Check the address space and permissions */
8083f520078SBALATON Zoltan     if (access_type == MMU_INST_FETCH) {
8093f520078SBALATON Zoltan         /* There is no way to fetch code using epid load */
8103f520078SBALATON Zoltan         assert(!use_epid);
8113f520078SBALATON Zoltan         as = FIELD_EX64(env->msr, MSR, IR);
8123f520078SBALATON Zoltan     }
8133f520078SBALATON Zoltan 
8143f520078SBALATON Zoltan     if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
8153f520078SBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
8163f520078SBALATON Zoltan         return -1;
8173f520078SBALATON Zoltan     }
8183f520078SBALATON Zoltan 
819750fbe33SBALATON Zoltan     *prot = 0;
8205118ebe8SLucas Mateus Castro (alqotel)     if (pr) {
8215118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_UR) {
822750fbe33SBALATON Zoltan             *prot |= PAGE_READ;
8235118ebe8SLucas Mateus Castro (alqotel)         }
8245118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_UW) {
825750fbe33SBALATON Zoltan             *prot |= PAGE_WRITE;
8265118ebe8SLucas Mateus Castro (alqotel)         }
8275118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_UX) {
828750fbe33SBALATON Zoltan             *prot |= PAGE_EXEC;
8295118ebe8SLucas Mateus Castro (alqotel)         }
8305118ebe8SLucas Mateus Castro (alqotel)     } else {
8315118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_SR) {
832750fbe33SBALATON Zoltan             *prot |= PAGE_READ;
8335118ebe8SLucas Mateus Castro (alqotel)         }
8345118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_SW) {
835750fbe33SBALATON Zoltan             *prot |= PAGE_WRITE;
8365118ebe8SLucas Mateus Castro (alqotel)         }
8375118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_SX) {
838750fbe33SBALATON Zoltan             *prot |= PAGE_EXEC;
8395118ebe8SLucas Mateus Castro (alqotel)         }
8405118ebe8SLucas Mateus Castro (alqotel)     }
841750fbe33SBALATON Zoltan     if (*prot & prot_for_access_type(access_type)) {
84256964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
8435118ebe8SLucas Mateus Castro (alqotel)         return 0;
8445118ebe8SLucas Mateus Castro (alqotel)     }
8455118ebe8SLucas Mateus Castro (alqotel) 
846750fbe33SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot);
8475118ebe8SLucas Mateus Castro (alqotel)     return access_type == MMU_INST_FETCH ? -3 : -2;
8485118ebe8SLucas Mateus Castro (alqotel) }
8495118ebe8SLucas Mateus Castro (alqotel) 
850e8a9c0fbSBALATON Zoltan static int mmubooke206_get_physical_address(CPUPPCState *env, hwaddr *raddr,
851e8a9c0fbSBALATON Zoltan                                             int *prot, target_ulong address,
8525118ebe8SLucas Mateus Castro (alqotel)                                             MMUAccessType access_type,
8535118ebe8SLucas Mateus Castro (alqotel)                                             int mmu_idx)
8545118ebe8SLucas Mateus Castro (alqotel) {
8555118ebe8SLucas Mateus Castro (alqotel)     ppcmas_tlb_t *tlb;
856e8a9c0fbSBALATON Zoltan     int i, j, ret = -1;
8575118ebe8SLucas Mateus Castro (alqotel) 
8585118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
8595118ebe8SLucas Mateus Castro (alqotel)         int ways = booke206_tlb_ways(env, i);
8605118ebe8SLucas Mateus Castro (alqotel)         for (j = 0; j < ways; j++) {
8615118ebe8SLucas Mateus Castro (alqotel)             tlb = booke206_get_tlbm(env, i, address, j);
8625118ebe8SLucas Mateus Castro (alqotel)             if (!tlb) {
8635118ebe8SLucas Mateus Castro (alqotel)                 continue;
8645118ebe8SLucas Mateus Castro (alqotel)             }
865e8a9c0fbSBALATON Zoltan             ret = mmubooke206_check_tlb(env, tlb, raddr, prot, address,
8665118ebe8SLucas Mateus Castro (alqotel)                                         access_type, mmu_idx);
8675118ebe8SLucas Mateus Castro (alqotel)             if (ret != -1) {
8685118ebe8SLucas Mateus Castro (alqotel)                 goto found_tlb;
8695118ebe8SLucas Mateus Castro (alqotel)             }
8705118ebe8SLucas Mateus Castro (alqotel)         }
8715118ebe8SLucas Mateus Castro (alqotel)     }
8725118ebe8SLucas Mateus Castro (alqotel) 
8735118ebe8SLucas Mateus Castro (alqotel) found_tlb:
8745118ebe8SLucas Mateus Castro (alqotel) 
875e8a9c0fbSBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => "
876e8a9c0fbSBALATON Zoltan                   HWADDR_FMT_plx " %d %d\n", __func__,
877e8a9c0fbSBALATON Zoltan                   ret < 0 ? "refused" : "granted", address,
878e8a9c0fbSBALATON Zoltan                   ret < 0 ? -1 : *raddr, ret == -1 ? 0 : *prot, ret);
8795118ebe8SLucas Mateus Castro (alqotel)     return ret;
8805118ebe8SLucas Mateus Castro (alqotel) }
8815118ebe8SLucas Mateus Castro (alqotel) 
8825118ebe8SLucas Mateus Castro (alqotel) static const char *book3e_tsize_to_str[32] = {
8835118ebe8SLucas Mateus Castro (alqotel)     "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
8845118ebe8SLucas Mateus Castro (alqotel)     "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
8855118ebe8SLucas Mateus Castro (alqotel)     "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
8865118ebe8SLucas Mateus Castro (alqotel)     "1T", "2T"
8875118ebe8SLucas Mateus Castro (alqotel) };
8885118ebe8SLucas Mateus Castro (alqotel) 
8895118ebe8SLucas Mateus Castro (alqotel) static void mmubooke_dump_mmu(CPUPPCState *env)
8905118ebe8SLucas Mateus Castro (alqotel) {
8915118ebe8SLucas Mateus Castro (alqotel)     ppcemb_tlb_t *entry;
8925118ebe8SLucas Mateus Castro (alqotel)     int i;
8935118ebe8SLucas Mateus Castro (alqotel) 
89405739977SPhilippe Mathieu-Daudé #ifdef CONFIG_KVM
8955118ebe8SLucas Mateus Castro (alqotel)     if (kvm_enabled() && !env->kvm_sw_tlb) {
8965118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("Cannot access KVM TLB\n");
8975118ebe8SLucas Mateus Castro (alqotel)         return;
8985118ebe8SLucas Mateus Castro (alqotel)     }
89905739977SPhilippe Mathieu-Daudé #endif
9005118ebe8SLucas Mateus Castro (alqotel) 
9015118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nTLB:\n");
9025118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("Effective          Physical           Size PID   Prot     "
9035118ebe8SLucas Mateus Castro (alqotel)                 "Attr\n");
9045118ebe8SLucas Mateus Castro (alqotel) 
9055118ebe8SLucas Mateus Castro (alqotel)     entry = &env->tlb.tlbe[0];
9065118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_tlb; i++, entry++) {
9075118ebe8SLucas Mateus Castro (alqotel)         hwaddr ea, pa;
9085118ebe8SLucas Mateus Castro (alqotel)         target_ulong mask;
9095118ebe8SLucas Mateus Castro (alqotel)         uint64_t size = (uint64_t)entry->size;
9105118ebe8SLucas Mateus Castro (alqotel)         char size_buf[20];
9115118ebe8SLucas Mateus Castro (alqotel) 
9125118ebe8SLucas Mateus Castro (alqotel)         /* Check valid flag */
9135118ebe8SLucas Mateus Castro (alqotel)         if (!(entry->prot & PAGE_VALID)) {
9145118ebe8SLucas Mateus Castro (alqotel)             continue;
9155118ebe8SLucas Mateus Castro (alqotel)         }
9165118ebe8SLucas Mateus Castro (alqotel) 
9175118ebe8SLucas Mateus Castro (alqotel)         mask = ~(entry->size - 1);
9185118ebe8SLucas Mateus Castro (alqotel)         ea = entry->EPN & mask;
9195118ebe8SLucas Mateus Castro (alqotel)         pa = entry->RPN & mask;
9205118ebe8SLucas Mateus Castro (alqotel)         /* Extend the physical address to 36 bits */
9215118ebe8SLucas Mateus Castro (alqotel)         pa |= (hwaddr)(entry->RPN & 0xF) << 32;
9225118ebe8SLucas Mateus Castro (alqotel)         if (size >= 1 * MiB) {
9235118ebe8SLucas Mateus Castro (alqotel)             snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / MiB);
9245118ebe8SLucas Mateus Castro (alqotel)         } else {
9255118ebe8SLucas Mateus Castro (alqotel)             snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size / KiB);
9265118ebe8SLucas Mateus Castro (alqotel)         }
9275118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
9285118ebe8SLucas Mateus Castro (alqotel)                     (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
9295118ebe8SLucas Mateus Castro (alqotel)                     entry->prot, entry->attr);
9305118ebe8SLucas Mateus Castro (alqotel)     }
9315118ebe8SLucas Mateus Castro (alqotel) 
9325118ebe8SLucas Mateus Castro (alqotel) }
9335118ebe8SLucas Mateus Castro (alqotel) 
9345118ebe8SLucas Mateus Castro (alqotel) static void mmubooke206_dump_one_tlb(CPUPPCState *env, int tlbn, int offset,
9355118ebe8SLucas Mateus Castro (alqotel)                                      int tlbsize)
9365118ebe8SLucas Mateus Castro (alqotel) {
9375118ebe8SLucas Mateus Castro (alqotel)     ppcmas_tlb_t *entry;
9385118ebe8SLucas Mateus Castro (alqotel)     int i;
9395118ebe8SLucas Mateus Castro (alqotel) 
9405118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nTLB%d:\n", tlbn);
9415118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("Effective          Physical           Size TID   TS SRWX"
9425118ebe8SLucas Mateus Castro (alqotel)                 " URWX WIMGE U0123\n");
9435118ebe8SLucas Mateus Castro (alqotel) 
9445118ebe8SLucas Mateus Castro (alqotel)     entry = &env->tlb.tlbm[offset];
9455118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < tlbsize; i++, entry++) {
9465118ebe8SLucas Mateus Castro (alqotel)         hwaddr ea, pa, size;
9475118ebe8SLucas Mateus Castro (alqotel)         int tsize;
9485118ebe8SLucas Mateus Castro (alqotel) 
9495118ebe8SLucas Mateus Castro (alqotel)         if (!(entry->mas1 & MAS1_VALID)) {
9505118ebe8SLucas Mateus Castro (alqotel)             continue;
9515118ebe8SLucas Mateus Castro (alqotel)         }
9525118ebe8SLucas Mateus Castro (alqotel) 
9535118ebe8SLucas Mateus Castro (alqotel)         tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
9545118ebe8SLucas Mateus Castro (alqotel)         size = 1024ULL << tsize;
9555118ebe8SLucas Mateus Castro (alqotel)         ea = entry->mas2 & ~(size - 1);
9565118ebe8SLucas Mateus Castro (alqotel)         pa = entry->mas7_3 & ~(size - 1);
9575118ebe8SLucas Mateus Castro (alqotel) 
9585118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u  S%c%c%c"
9595118ebe8SLucas Mateus Castro (alqotel)                     " U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
9605118ebe8SLucas Mateus Castro (alqotel)                     (uint64_t)ea, (uint64_t)pa,
9615118ebe8SLucas Mateus Castro (alqotel)                     book3e_tsize_to_str[tsize],
9625118ebe8SLucas Mateus Castro (alqotel)                     (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
9635118ebe8SLucas Mateus Castro (alqotel)                     (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
9645118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_SR ? 'R' : '-',
9655118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_SW ? 'W' : '-',
9665118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_SX ? 'X' : '-',
9675118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_UR ? 'R' : '-',
9685118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_UW ? 'W' : '-',
9695118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_UX ? 'X' : '-',
9705118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_W ? 'W' : '-',
9715118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_I ? 'I' : '-',
9725118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_M ? 'M' : '-',
9735118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_G ? 'G' : '-',
9745118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_E ? 'E' : '-',
9755118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U0 ? '0' : '-',
9765118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U1 ? '1' : '-',
9775118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U2 ? '2' : '-',
9785118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U3 ? '3' : '-');
9795118ebe8SLucas Mateus Castro (alqotel)     }
9805118ebe8SLucas Mateus Castro (alqotel) }
9815118ebe8SLucas Mateus Castro (alqotel) 
9825118ebe8SLucas Mateus Castro (alqotel) static void mmubooke206_dump_mmu(CPUPPCState *env)
9835118ebe8SLucas Mateus Castro (alqotel) {
9845118ebe8SLucas Mateus Castro (alqotel)     int offset = 0;
9855118ebe8SLucas Mateus Castro (alqotel)     int i;
9865118ebe8SLucas Mateus Castro (alqotel) 
98705739977SPhilippe Mathieu-Daudé #ifdef CONFIG_KVM
9885118ebe8SLucas Mateus Castro (alqotel)     if (kvm_enabled() && !env->kvm_sw_tlb) {
9895118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("Cannot access KVM TLB\n");
9905118ebe8SLucas Mateus Castro (alqotel)         return;
9915118ebe8SLucas Mateus Castro (alqotel)     }
99205739977SPhilippe Mathieu-Daudé #endif
9935118ebe8SLucas Mateus Castro (alqotel) 
9945118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
9955118ebe8SLucas Mateus Castro (alqotel)         int size = booke206_tlb_size(env, i);
9965118ebe8SLucas Mateus Castro (alqotel) 
9975118ebe8SLucas Mateus Castro (alqotel)         if (size == 0) {
9985118ebe8SLucas Mateus Castro (alqotel)             continue;
9995118ebe8SLucas Mateus Castro (alqotel)         }
10005118ebe8SLucas Mateus Castro (alqotel) 
10015118ebe8SLucas Mateus Castro (alqotel)         mmubooke206_dump_one_tlb(env, i, offset, size);
10025118ebe8SLucas Mateus Castro (alqotel)         offset += size;
10035118ebe8SLucas Mateus Castro (alqotel)     }
10045118ebe8SLucas Mateus Castro (alqotel) }
10055118ebe8SLucas Mateus Castro (alqotel) 
10065118ebe8SLucas Mateus Castro (alqotel) static void mmu6xx_dump_BATs(CPUPPCState *env, int type)
10075118ebe8SLucas Mateus Castro (alqotel) {
10085118ebe8SLucas Mateus Castro (alqotel)     target_ulong *BATlt, *BATut, *BATu, *BATl;
10095118ebe8SLucas Mateus Castro (alqotel)     target_ulong BEPIl, BEPIu, bl;
10105118ebe8SLucas Mateus Castro (alqotel)     int i;
10115118ebe8SLucas Mateus Castro (alqotel) 
10125118ebe8SLucas Mateus Castro (alqotel)     switch (type) {
10135118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_CODE:
10145118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->IBAT[1];
10155118ebe8SLucas Mateus Castro (alqotel)         BATut = env->IBAT[0];
10165118ebe8SLucas Mateus Castro (alqotel)         break;
10175118ebe8SLucas Mateus Castro (alqotel)     default:
10185118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->DBAT[1];
10195118ebe8SLucas Mateus Castro (alqotel)         BATut = env->DBAT[0];
10205118ebe8SLucas Mateus Castro (alqotel)         break;
10215118ebe8SLucas Mateus Castro (alqotel)     }
10225118ebe8SLucas Mateus Castro (alqotel) 
10235118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_BATs; i++) {
10245118ebe8SLucas Mateus Castro (alqotel)         BATu = &BATut[i];
10255118ebe8SLucas Mateus Castro (alqotel)         BATl = &BATlt[i];
10265118ebe8SLucas Mateus Castro (alqotel)         BEPIu = *BATu & 0xF0000000;
10275118ebe8SLucas Mateus Castro (alqotel)         BEPIl = *BATu & 0x0FFE0000;
10285118ebe8SLucas Mateus Castro (alqotel)         bl = (*BATu & 0x00001FFC) << 15;
10295118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("%s BAT%d BATu " TARGET_FMT_lx
10305118ebe8SLucas Mateus Castro (alqotel)                     " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
10315118ebe8SLucas Mateus Castro (alqotel)                     TARGET_FMT_lx " " TARGET_FMT_lx "\n",
10325118ebe8SLucas Mateus Castro (alqotel)                     type == ACCESS_CODE ? "code" : "data", i,
10335118ebe8SLucas Mateus Castro (alqotel)                     *BATu, *BATl, BEPIu, BEPIl, bl);
10345118ebe8SLucas Mateus Castro (alqotel)     }
10355118ebe8SLucas Mateus Castro (alqotel) }
10365118ebe8SLucas Mateus Castro (alqotel) 
10375118ebe8SLucas Mateus Castro (alqotel) static void mmu6xx_dump_mmu(CPUPPCState *env)
10385118ebe8SLucas Mateus Castro (alqotel) {
10395118ebe8SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = env_archcpu(env);
10405118ebe8SLucas Mateus Castro (alqotel)     ppc6xx_tlb_t *tlb;
10415118ebe8SLucas Mateus Castro (alqotel)     target_ulong sr;
10425118ebe8SLucas Mateus Castro (alqotel)     int type, way, entry, i;
10435118ebe8SLucas Mateus Castro (alqotel) 
10445118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu));
10455118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu));
10465118ebe8SLucas Mateus Castro (alqotel) 
10475118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nSegment registers:\n");
10485118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < 32; i++) {
10495118ebe8SLucas Mateus Castro (alqotel)         sr = env->sr[i];
10505118ebe8SLucas Mateus Castro (alqotel)         if (sr & 0x80000000) {
10515118ebe8SLucas Mateus Castro (alqotel)             qemu_printf("%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
10525118ebe8SLucas Mateus Castro (alqotel)                         "CNTLR_SPEC=0x%05x\n", i,
10535118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
10545118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
10555118ebe8SLucas Mateus Castro (alqotel)                         (uint32_t)(sr & 0xFFFFF));
10565118ebe8SLucas Mateus Castro (alqotel)         } else {
10575118ebe8SLucas Mateus Castro (alqotel)             qemu_printf("%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
10585118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
10595118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
10605118ebe8SLucas Mateus Castro (alqotel)                         (uint32_t)(sr & 0x00FFFFFF));
10615118ebe8SLucas Mateus Castro (alqotel)         }
10625118ebe8SLucas Mateus Castro (alqotel)     }
10635118ebe8SLucas Mateus Castro (alqotel) 
10645118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nBATs:\n");
10655118ebe8SLucas Mateus Castro (alqotel)     mmu6xx_dump_BATs(env, ACCESS_INT);
10665118ebe8SLucas Mateus Castro (alqotel)     mmu6xx_dump_BATs(env, ACCESS_CODE);
10675118ebe8SLucas Mateus Castro (alqotel) 
10685118ebe8SLucas Mateus Castro (alqotel)     if (env->id_tlbs != 1) {
10695118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("ERROR: 6xx MMU should have separated TLB"
10705118ebe8SLucas Mateus Castro (alqotel)                     " for code and data\n");
10715118ebe8SLucas Mateus Castro (alqotel)     }
10725118ebe8SLucas Mateus Castro (alqotel) 
10735118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nTLBs                       [EPN    EPN + SIZE]\n");
10745118ebe8SLucas Mateus Castro (alqotel) 
10755118ebe8SLucas Mateus Castro (alqotel)     for (type = 0; type < 2; type++) {
10765118ebe8SLucas Mateus Castro (alqotel)         for (way = 0; way < env->nb_ways; way++) {
10775118ebe8SLucas Mateus Castro (alqotel)             for (entry = env->nb_tlb * type + env->tlb_per_way * way;
10785118ebe8SLucas Mateus Castro (alqotel)                  entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
10795118ebe8SLucas Mateus Castro (alqotel)                  entry++) {
10805118ebe8SLucas Mateus Castro (alqotel) 
10815118ebe8SLucas Mateus Castro (alqotel)                 tlb = &env->tlb.tlb6[entry];
10825118ebe8SLucas Mateus Castro (alqotel)                 qemu_printf("%s TLB %02d/%02d way:%d %s ["
10835118ebe8SLucas Mateus Castro (alqotel)                             TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
10845118ebe8SLucas Mateus Castro (alqotel)                             type ? "code" : "data", entry % env->nb_tlb,
10855118ebe8SLucas Mateus Castro (alqotel)                             env->nb_tlb, way,
10865118ebe8SLucas Mateus Castro (alqotel)                             pte_is_valid(tlb->pte0) ? "valid" : "inval",
10875118ebe8SLucas Mateus Castro (alqotel)                             tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
10885118ebe8SLucas Mateus Castro (alqotel)             }
10895118ebe8SLucas Mateus Castro (alqotel)         }
10905118ebe8SLucas Mateus Castro (alqotel)     }
10915118ebe8SLucas Mateus Castro (alqotel) }
10925118ebe8SLucas Mateus Castro (alqotel) 
10935118ebe8SLucas Mateus Castro (alqotel) void dump_mmu(CPUPPCState *env)
10945118ebe8SLucas Mateus Castro (alqotel) {
10955118ebe8SLucas Mateus Castro (alqotel)     switch (env->mmu_model) {
10965118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_BOOKE:
10975118ebe8SLucas Mateus Castro (alqotel)         mmubooke_dump_mmu(env);
10985118ebe8SLucas Mateus Castro (alqotel)         break;
10995118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_BOOKE206:
11005118ebe8SLucas Mateus Castro (alqotel)         mmubooke206_dump_mmu(env);
11015118ebe8SLucas Mateus Castro (alqotel)         break;
11025118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_SOFT_6xx:
11035118ebe8SLucas Mateus Castro (alqotel)         mmu6xx_dump_mmu(env);
11045118ebe8SLucas Mateus Castro (alqotel)         break;
11055118ebe8SLucas Mateus Castro (alqotel) #if defined(TARGET_PPC64)
11065118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_64B:
11075118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_03:
11085118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_06:
11095118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_07:
11105118ebe8SLucas Mateus Castro (alqotel)         dump_slb(env_archcpu(env));
11115118ebe8SLucas Mateus Castro (alqotel)         break;
11125118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_3_00:
11135118ebe8SLucas Mateus Castro (alqotel)         if (ppc64_v3_radix(env_archcpu(env))) {
11145118ebe8SLucas Mateus Castro (alqotel)             qemu_log_mask(LOG_UNIMP, "%s: the PPC64 MMU is unsupported\n",
11155118ebe8SLucas Mateus Castro (alqotel)                           __func__);
11165118ebe8SLucas Mateus Castro (alqotel)         } else {
11175118ebe8SLucas Mateus Castro (alqotel)             dump_slb(env_archcpu(env));
11185118ebe8SLucas Mateus Castro (alqotel)         }
11195118ebe8SLucas Mateus Castro (alqotel)         break;
11205118ebe8SLucas Mateus Castro (alqotel) #endif
11215118ebe8SLucas Mateus Castro (alqotel)     default:
11225118ebe8SLucas Mateus Castro (alqotel)         qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
11235118ebe8SLucas Mateus Castro (alqotel)     }
11245118ebe8SLucas Mateus Castro (alqotel) }
11255118ebe8SLucas Mateus Castro (alqotel) 
11265118ebe8SLucas Mateus Castro (alqotel) static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
11275118ebe8SLucas Mateus Castro (alqotel)                                          MMUAccessType access_type, int mmu_idx)
11285118ebe8SLucas Mateus Castro (alqotel) {
11295118ebe8SLucas Mateus Castro (alqotel)     uint32_t epid;
11305118ebe8SLucas Mateus Castro (alqotel)     bool as, pr;
11315118ebe8SLucas Mateus Castro (alqotel)     uint32_t missed_tid = 0;
11325118ebe8SLucas Mateus Castro (alqotel)     bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
11335118ebe8SLucas Mateus Castro (alqotel) 
11345118ebe8SLucas Mateus Castro (alqotel)     if (access_type == MMU_INST_FETCH) {
11354d979c9fSVíctor Colombo         as = FIELD_EX64(env->msr, MSR, IR);
11365118ebe8SLucas Mateus Castro (alqotel)     }
11375118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
11385118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
11395118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
11405118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS3] = 0;
11415118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS6] = 0;
11425118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS7] = 0;
11435118ebe8SLucas Mateus Castro (alqotel) 
11445118ebe8SLucas Mateus Castro (alqotel)     /* AS */
11455118ebe8SLucas Mateus Castro (alqotel)     if (as) {
11465118ebe8SLucas Mateus Castro (alqotel)         env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
11475118ebe8SLucas Mateus Castro (alqotel)         env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
11485118ebe8SLucas Mateus Castro (alqotel)     }
11495118ebe8SLucas Mateus Castro (alqotel) 
11505118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
11515118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
11525118ebe8SLucas Mateus Castro (alqotel) 
11535118ebe8SLucas Mateus Castro (alqotel)     if (!use_epid) {
11545118ebe8SLucas Mateus Castro (alqotel)         switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
11555118ebe8SLucas Mateus Castro (alqotel)         case MAS4_TIDSELD_PID0:
11565118ebe8SLucas Mateus Castro (alqotel)             missed_tid = env->spr[SPR_BOOKE_PID];
11575118ebe8SLucas Mateus Castro (alqotel)             break;
11585118ebe8SLucas Mateus Castro (alqotel)         case MAS4_TIDSELD_PID1:
11595118ebe8SLucas Mateus Castro (alqotel)             missed_tid = env->spr[SPR_BOOKE_PID1];
11605118ebe8SLucas Mateus Castro (alqotel)             break;
11615118ebe8SLucas Mateus Castro (alqotel)         case MAS4_TIDSELD_PID2:
11625118ebe8SLucas Mateus Castro (alqotel)             missed_tid = env->spr[SPR_BOOKE_PID2];
11635118ebe8SLucas Mateus Castro (alqotel)             break;
11645118ebe8SLucas Mateus Castro (alqotel)         }
11655118ebe8SLucas Mateus Castro (alqotel)         env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
11665118ebe8SLucas Mateus Castro (alqotel)     } else {
11675118ebe8SLucas Mateus Castro (alqotel)         missed_tid = epid;
11685118ebe8SLucas Mateus Castro (alqotel)         env->spr[SPR_BOOKE_MAS6] |= missed_tid << 16;
11695118ebe8SLucas Mateus Castro (alqotel)     }
11705118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS1] |= (missed_tid << MAS1_TID_SHIFT);
11715118ebe8SLucas Mateus Castro (alqotel) 
11725118ebe8SLucas Mateus Castro (alqotel) 
11735118ebe8SLucas Mateus Castro (alqotel)     /* next victim logic */
11745118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
11755118ebe8SLucas Mateus Castro (alqotel)     env->last_way++;
11765118ebe8SLucas Mateus Castro (alqotel)     env->last_way &= booke206_tlb_ways(env, 0) - 1;
11775118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
11785118ebe8SLucas Mateus Castro (alqotel) }
11795118ebe8SLucas Mateus Castro (alqotel) 
1180ba91e5d0SBALATON Zoltan static bool ppc_booke_xlate(PowerPCCPU *cpu, vaddr eaddr,
1181ba91e5d0SBALATON Zoltan                             MMUAccessType access_type,
1182ba91e5d0SBALATON Zoltan                             hwaddr *raddrp, int *psizep, int *protp,
1183ba91e5d0SBALATON Zoltan                             int mmu_idx, bool guest_visible)
1184ba91e5d0SBALATON Zoltan {
1185ba91e5d0SBALATON Zoltan     CPUState *cs = CPU(cpu);
1186ba91e5d0SBALATON Zoltan     CPUPPCState *env = &cpu->env;
1187ba91e5d0SBALATON Zoltan     hwaddr raddr;
1188ba91e5d0SBALATON Zoltan     int prot, ret;
1189ba91e5d0SBALATON Zoltan 
1190ba91e5d0SBALATON Zoltan     if (env->mmu_model == POWERPC_MMU_BOOKE206) {
1191ba91e5d0SBALATON Zoltan         ret = mmubooke206_get_physical_address(env, &raddr, &prot, eaddr,
1192ba91e5d0SBALATON Zoltan                                                access_type, mmu_idx);
1193ba91e5d0SBALATON Zoltan     } else {
1194ba91e5d0SBALATON Zoltan         ret = mmubooke_get_physical_address(env, &raddr, &prot, eaddr,
1195ba91e5d0SBALATON Zoltan                                             access_type);
1196ba91e5d0SBALATON Zoltan     }
1197ba91e5d0SBALATON Zoltan     if (ret == 0) {
1198ba91e5d0SBALATON Zoltan         *raddrp = raddr;
1199ba91e5d0SBALATON Zoltan         *protp = prot;
1200ba91e5d0SBALATON Zoltan         *psizep = TARGET_PAGE_BITS;
1201ba91e5d0SBALATON Zoltan         return true;
1202ba91e5d0SBALATON Zoltan     } else if (!guest_visible) {
1203ba91e5d0SBALATON Zoltan         return false;
1204ba91e5d0SBALATON Zoltan     }
1205ba91e5d0SBALATON Zoltan 
1206ba91e5d0SBALATON Zoltan     log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
1207aa20e1c8SBALATON Zoltan     env->error_code = 0;
1208ba91e5d0SBALATON Zoltan     switch (ret) {
1209ba91e5d0SBALATON Zoltan     case -1:
1210ba91e5d0SBALATON Zoltan         /* No matches in page tables or TLB */
1211b18489b3SBALATON Zoltan         if (env->mmu_model == POWERPC_MMU_BOOKE206) {
1212b18489b3SBALATON Zoltan             booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
1213b18489b3SBALATON Zoltan         }
1214b18489b3SBALATON Zoltan         cs->exception_index = (access_type == MMU_INST_FETCH) ?
1215b18489b3SBALATON Zoltan                               POWERPC_EXCP_ITLB : POWERPC_EXCP_DTLB;
1216ba91e5d0SBALATON Zoltan         env->spr[SPR_BOOKE_DEAR] = eaddr;
1217ba91e5d0SBALATON Zoltan         env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
1218ba91e5d0SBALATON Zoltan         break;
1219ba91e5d0SBALATON Zoltan     case -2:
1220ba91e5d0SBALATON Zoltan         /* Access rights violation */
1221b18489b3SBALATON Zoltan         cs->exception_index = (access_type == MMU_INST_FETCH) ?
1222b18489b3SBALATON Zoltan                               POWERPC_EXCP_ISI : POWERPC_EXCP_DSI;
1223b18489b3SBALATON Zoltan         if (access_type != MMU_INST_FETCH) {
1224b18489b3SBALATON Zoltan             env->spr[SPR_BOOKE_DEAR] = eaddr;
1225b18489b3SBALATON Zoltan             env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
1226b18489b3SBALATON Zoltan         }
1227ba91e5d0SBALATON Zoltan         break;
1228ba91e5d0SBALATON Zoltan     case -3:
1229ba91e5d0SBALATON Zoltan         /* No execute protection violation */
1230ba91e5d0SBALATON Zoltan         cs->exception_index = POWERPC_EXCP_ISI;
1231ba91e5d0SBALATON Zoltan         env->spr[SPR_BOOKE_ESR] = 0;
1232ba91e5d0SBALATON Zoltan         break;
1233ba91e5d0SBALATON Zoltan     }
1234b18489b3SBALATON Zoltan 
1235ba91e5d0SBALATON Zoltan     return false;
1236ba91e5d0SBALATON Zoltan }
1237ba91e5d0SBALATON Zoltan 
1238c29f808aSBALATON Zoltan static bool ppc_real_mode_xlate(PowerPCCPU *cpu, vaddr eaddr,
1239c29f808aSBALATON Zoltan                                 MMUAccessType access_type,
1240c29f808aSBALATON Zoltan                                 hwaddr *raddrp, int *psizep, int *protp)
1241c29f808aSBALATON Zoltan {
1242c29f808aSBALATON Zoltan     CPUPPCState *env = &cpu->env;
1243c29f808aSBALATON Zoltan 
1244c29f808aSBALATON Zoltan     if (access_type == MMU_INST_FETCH ? !FIELD_EX64(env->msr, MSR, IR)
1245c29f808aSBALATON Zoltan                                       : !FIELD_EX64(env->msr, MSR, DR)) {
1246c29f808aSBALATON Zoltan         *raddrp = eaddr;
1247c29f808aSBALATON Zoltan         *protp = PAGE_RWX;
1248c29f808aSBALATON Zoltan         *psizep = TARGET_PAGE_BITS;
1249c29f808aSBALATON Zoltan         return true;
1250c29f808aSBALATON Zoltan     } else if (env->mmu_model == POWERPC_MMU_REAL) {
1251c29f808aSBALATON Zoltan         cpu_abort(CPU(cpu), "PowerPC in real mode shold not do translation\n");
1252c29f808aSBALATON Zoltan     }
1253c29f808aSBALATON Zoltan     return false;
1254c29f808aSBALATON Zoltan }
1255c29f808aSBALATON Zoltan 
125658b01325SBALATON Zoltan static bool ppc_40x_xlate(PowerPCCPU *cpu, vaddr eaddr,
125758b01325SBALATON Zoltan                           MMUAccessType access_type,
125858b01325SBALATON Zoltan                           hwaddr *raddrp, int *psizep, int *protp,
125958b01325SBALATON Zoltan                           int mmu_idx, bool guest_visible)
126058b01325SBALATON Zoltan {
126158b01325SBALATON Zoltan     CPUState *cs = CPU(cpu);
126258b01325SBALATON Zoltan     CPUPPCState *env = &cpu->env;
126358b01325SBALATON Zoltan     int ret;
126458b01325SBALATON Zoltan 
126558b01325SBALATON Zoltan     if (ppc_real_mode_xlate(cpu, eaddr, access_type, raddrp, psizep, protp)) {
126658b01325SBALATON Zoltan         return true;
126758b01325SBALATON Zoltan     }
126858b01325SBALATON Zoltan 
126958b01325SBALATON Zoltan     ret = mmu40x_get_physical_address(env, raddrp, protp, eaddr, access_type);
127058b01325SBALATON Zoltan     if (ret == 0) {
127158b01325SBALATON Zoltan         *psizep = TARGET_PAGE_BITS;
127258b01325SBALATON Zoltan         return true;
127358b01325SBALATON Zoltan     } else if (!guest_visible) {
127458b01325SBALATON Zoltan         return false;
127558b01325SBALATON Zoltan     }
127658b01325SBALATON Zoltan 
127758b01325SBALATON Zoltan     log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
127858b01325SBALATON Zoltan     if (access_type == MMU_INST_FETCH) {
127958b01325SBALATON Zoltan         switch (ret) {
128058b01325SBALATON Zoltan         case -1:
128158b01325SBALATON Zoltan             /* No matches in page tables or TLB */
128258b01325SBALATON Zoltan             cs->exception_index = POWERPC_EXCP_ITLB;
128358b01325SBALATON Zoltan             env->error_code = 0;
128458b01325SBALATON Zoltan             env->spr[SPR_40x_DEAR] = eaddr;
128558b01325SBALATON Zoltan             env->spr[SPR_40x_ESR] = 0x00000000;
128658b01325SBALATON Zoltan             break;
128758b01325SBALATON Zoltan         case -2:
128858b01325SBALATON Zoltan             /* Access rights violation */
128958b01325SBALATON Zoltan             cs->exception_index = POWERPC_EXCP_ISI;
129058b01325SBALATON Zoltan             env->error_code = 0x08000000;
129158b01325SBALATON Zoltan             break;
129258b01325SBALATON Zoltan         default:
129358b01325SBALATON Zoltan             g_assert_not_reached();
129458b01325SBALATON Zoltan         }
129558b01325SBALATON Zoltan     } else {
129658b01325SBALATON Zoltan         switch (ret) {
129758b01325SBALATON Zoltan         case -1:
129858b01325SBALATON Zoltan             /* No matches in page tables or TLB */
129958b01325SBALATON Zoltan             cs->exception_index = POWERPC_EXCP_DTLB;
130058b01325SBALATON Zoltan             env->error_code = 0;
130158b01325SBALATON Zoltan             env->spr[SPR_40x_DEAR] = eaddr;
130258b01325SBALATON Zoltan             if (access_type == MMU_DATA_STORE) {
130358b01325SBALATON Zoltan                 env->spr[SPR_40x_ESR] = 0x00800000;
130458b01325SBALATON Zoltan             } else {
130558b01325SBALATON Zoltan                 env->spr[SPR_40x_ESR] = 0x00000000;
130658b01325SBALATON Zoltan             }
130758b01325SBALATON Zoltan             break;
130858b01325SBALATON Zoltan         case -2:
130958b01325SBALATON Zoltan             /* Access rights violation */
131058b01325SBALATON Zoltan             cs->exception_index = POWERPC_EXCP_DSI;
131158b01325SBALATON Zoltan             env->error_code = 0;
131258b01325SBALATON Zoltan             env->spr[SPR_40x_DEAR] = eaddr;
131358b01325SBALATON Zoltan             if (access_type == MMU_DATA_STORE) {
131458b01325SBALATON Zoltan                 env->spr[SPR_40x_ESR] |= 0x00800000;
131558b01325SBALATON Zoltan             }
131658b01325SBALATON Zoltan             break;
131758b01325SBALATON Zoltan         default:
131858b01325SBALATON Zoltan             g_assert_not_reached();
131958b01325SBALATON Zoltan         }
132058b01325SBALATON Zoltan     }
132158b01325SBALATON Zoltan     return false;
132258b01325SBALATON Zoltan }
132358b01325SBALATON Zoltan 
13246b9ea7f3SBALATON Zoltan static bool ppc_6xx_xlate(PowerPCCPU *cpu, vaddr eaddr,
13255118ebe8SLucas Mateus Castro (alqotel)                           MMUAccessType access_type,
13265118ebe8SLucas Mateus Castro (alqotel)                           hwaddr *raddrp, int *psizep, int *protp,
13275118ebe8SLucas Mateus Castro (alqotel)                           int mmu_idx, bool guest_visible)
13285118ebe8SLucas Mateus Castro (alqotel) {
13295118ebe8SLucas Mateus Castro (alqotel)     CPUState *cs = CPU(cpu);
13305118ebe8SLucas Mateus Castro (alqotel)     CPUPPCState *env = &cpu->env;
13315118ebe8SLucas Mateus Castro (alqotel)     mmu_ctx_t ctx;
13325118ebe8SLucas Mateus Castro (alqotel)     int type;
13335118ebe8SLucas Mateus Castro (alqotel)     int ret;
13345118ebe8SLucas Mateus Castro (alqotel) 
1335c29f808aSBALATON Zoltan     if (ppc_real_mode_xlate(cpu, eaddr, access_type, raddrp, psizep, protp)) {
1336c29f808aSBALATON Zoltan         return true;
1337c29f808aSBALATON Zoltan     }
1338c29f808aSBALATON Zoltan 
13395118ebe8SLucas Mateus Castro (alqotel)     if (access_type == MMU_INST_FETCH) {
13405118ebe8SLucas Mateus Castro (alqotel)         /* code access */
13415118ebe8SLucas Mateus Castro (alqotel)         type = ACCESS_CODE;
13425118ebe8SLucas Mateus Castro (alqotel)     } else if (guest_visible) {
13435118ebe8SLucas Mateus Castro (alqotel)         /* data access */
13445118ebe8SLucas Mateus Castro (alqotel)         type = env->access_type;
13455118ebe8SLucas Mateus Castro (alqotel)     } else {
13465118ebe8SLucas Mateus Castro (alqotel)         type = ACCESS_INT;
13475118ebe8SLucas Mateus Castro (alqotel)     }
13485118ebe8SLucas Mateus Castro (alqotel) 
13496b9ea7f3SBALATON Zoltan     ctx.prot = 0;
13506b9ea7f3SBALATON Zoltan     ctx.hash[0] = 0;
13516b9ea7f3SBALATON Zoltan     ctx.hash[1] = 0;
13526b9ea7f3SBALATON Zoltan     ret = mmu6xx_get_physical_address(env, &ctx, eaddr, access_type, type);
13535118ebe8SLucas Mateus Castro (alqotel)     if (ret == 0) {
13545118ebe8SLucas Mateus Castro (alqotel)         *raddrp = ctx.raddr;
13555118ebe8SLucas Mateus Castro (alqotel)         *protp = ctx.prot;
13565118ebe8SLucas Mateus Castro (alqotel)         *psizep = TARGET_PAGE_BITS;
13575118ebe8SLucas Mateus Castro (alqotel)         return true;
13589e9ca54cSBALATON Zoltan     } else if (!guest_visible) {
13599e9ca54cSBALATON Zoltan         return false;
13605118ebe8SLucas Mateus Castro (alqotel)     }
13615118ebe8SLucas Mateus Castro (alqotel) 
136256964585SCédric Le Goater     log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
13635118ebe8SLucas Mateus Castro (alqotel)     if (type == ACCESS_CODE) {
13645118ebe8SLucas Mateus Castro (alqotel)         switch (ret) {
13655118ebe8SLucas Mateus Castro (alqotel)         case -1:
13665118ebe8SLucas Mateus Castro (alqotel)             /* No matches in page tables or TLB */
13675118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_IFTLB;
13685118ebe8SLucas Mateus Castro (alqotel)             env->error_code = 1 << 18;
13695118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_IMISS] = eaddr;
13705118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
13715118ebe8SLucas Mateus Castro (alqotel)             goto tlb_miss;
13725118ebe8SLucas Mateus Castro (alqotel)         case -2:
13735118ebe8SLucas Mateus Castro (alqotel)             /* Access rights violation */
13745118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_ISI;
13755118ebe8SLucas Mateus Castro (alqotel)             env->error_code = 0x08000000;
13765118ebe8SLucas Mateus Castro (alqotel)             break;
13775118ebe8SLucas Mateus Castro (alqotel)         case -3:
13785118ebe8SLucas Mateus Castro (alqotel)             /* No execute protection violation */
13795118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_ISI;
1380ba91e5d0SBALATON Zoltan             env->error_code = 0x10000000;
13815118ebe8SLucas Mateus Castro (alqotel)             break;
13825118ebe8SLucas Mateus Castro (alqotel)         case -4:
13835118ebe8SLucas Mateus Castro (alqotel)             /* Direct store exception */
13845118ebe8SLucas Mateus Castro (alqotel)             /* No code fetch is allowed in direct-store areas */
13855118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_ISI;
13865118ebe8SLucas Mateus Castro (alqotel)             env->error_code = 0x10000000;
13875118ebe8SLucas Mateus Castro (alqotel)             break;
13885118ebe8SLucas Mateus Castro (alqotel)         }
13895118ebe8SLucas Mateus Castro (alqotel)     } else {
13905118ebe8SLucas Mateus Castro (alqotel)         switch (ret) {
13915118ebe8SLucas Mateus Castro (alqotel)         case -1:
13925118ebe8SLucas Mateus Castro (alqotel)             /* No matches in page tables or TLB */
13935118ebe8SLucas Mateus Castro (alqotel)             if (access_type == MMU_DATA_STORE) {
13945118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DSTLB;
13955118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 1 << 16;
13965118ebe8SLucas Mateus Castro (alqotel)             } else {
13975118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DLTLB;
13985118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 0;
13995118ebe8SLucas Mateus Castro (alqotel)             }
14005118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_DMISS] = eaddr;
14015118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
14025118ebe8SLucas Mateus Castro (alqotel) tlb_miss:
14035118ebe8SLucas Mateus Castro (alqotel)             env->error_code |= ctx.key << 19;
14045118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
14055118ebe8SLucas Mateus Castro (alqotel)                                   get_pteg_offset32(cpu, ctx.hash[0]);
14065118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
14075118ebe8SLucas Mateus Castro (alqotel)                                   get_pteg_offset32(cpu, ctx.hash[1]);
14085118ebe8SLucas Mateus Castro (alqotel)             break;
14095118ebe8SLucas Mateus Castro (alqotel)         case -2:
14105118ebe8SLucas Mateus Castro (alqotel)             /* Access rights violation */
14115118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_DSI;
14125118ebe8SLucas Mateus Castro (alqotel)             env->error_code = 0;
14135118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_DAR] = eaddr;
14145118ebe8SLucas Mateus Castro (alqotel)             if (access_type == MMU_DATA_STORE) {
14155118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DSISR] = 0x0A000000;
14165118ebe8SLucas Mateus Castro (alqotel)             } else {
14175118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DSISR] = 0x08000000;
14185118ebe8SLucas Mateus Castro (alqotel)             }
14195118ebe8SLucas Mateus Castro (alqotel)             break;
14205118ebe8SLucas Mateus Castro (alqotel)         case -4:
14215118ebe8SLucas Mateus Castro (alqotel)             /* Direct store exception */
14225118ebe8SLucas Mateus Castro (alqotel)             switch (type) {
14235118ebe8SLucas Mateus Castro (alqotel)             case ACCESS_FLOAT:
14245118ebe8SLucas Mateus Castro (alqotel)                 /* Floating point load/store */
14255118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_ALIGN;
14265118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = POWERPC_EXCP_ALIGN_FP;
14275118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DAR] = eaddr;
14285118ebe8SLucas Mateus Castro (alqotel)                 break;
14295118ebe8SLucas Mateus Castro (alqotel)             case ACCESS_RES:
14305118ebe8SLucas Mateus Castro (alqotel)                 /* lwarx, ldarx or stwcx. */
14315118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DSI;
14325118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 0;
14335118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DAR] = eaddr;
14345118ebe8SLucas Mateus Castro (alqotel)                 if (access_type == MMU_DATA_STORE) {
14355118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DSISR] = 0x06000000;
14365118ebe8SLucas Mateus Castro (alqotel)                 } else {
14375118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DSISR] = 0x04000000;
14385118ebe8SLucas Mateus Castro (alqotel)                 }
14395118ebe8SLucas Mateus Castro (alqotel)                 break;
14405118ebe8SLucas Mateus Castro (alqotel)             case ACCESS_EXT:
14415118ebe8SLucas Mateus Castro (alqotel)                 /* eciwx or ecowx */
14425118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DSI;
14435118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 0;
14445118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DAR] = eaddr;
14455118ebe8SLucas Mateus Castro (alqotel)                 if (access_type == MMU_DATA_STORE) {
14465118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DSISR] = 0x06100000;
14475118ebe8SLucas Mateus Castro (alqotel)                 } else {
14485118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DSISR] = 0x04100000;
14495118ebe8SLucas Mateus Castro (alqotel)                 }
14505118ebe8SLucas Mateus Castro (alqotel)                 break;
14515118ebe8SLucas Mateus Castro (alqotel)             default:
14525118ebe8SLucas Mateus Castro (alqotel)                 printf("DSI: invalid exception (%d)\n", ret);
14535118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_PROGRAM;
14549e9ca54cSBALATON Zoltan                 env->error_code = POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
14555118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DAR] = eaddr;
14565118ebe8SLucas Mateus Castro (alqotel)                 break;
14575118ebe8SLucas Mateus Castro (alqotel)             }
14585118ebe8SLucas Mateus Castro (alqotel)             break;
14595118ebe8SLucas Mateus Castro (alqotel)         }
14605118ebe8SLucas Mateus Castro (alqotel)     }
14615118ebe8SLucas Mateus Castro (alqotel)     return false;
14625118ebe8SLucas Mateus Castro (alqotel) }
14635118ebe8SLucas Mateus Castro (alqotel) 
14645118ebe8SLucas Mateus Castro (alqotel) /*****************************************************************************/
14655118ebe8SLucas Mateus Castro (alqotel) 
14665118ebe8SLucas Mateus Castro (alqotel) bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
14675118ebe8SLucas Mateus Castro (alqotel)                       hwaddr *raddrp, int *psizep, int *protp,
14685118ebe8SLucas Mateus Castro (alqotel)                       int mmu_idx, bool guest_visible)
14695118ebe8SLucas Mateus Castro (alqotel) {
14705118ebe8SLucas Mateus Castro (alqotel)     switch (cpu->env.mmu_model) {
14715118ebe8SLucas Mateus Castro (alqotel) #if defined(TARGET_PPC64)
14725118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_3_00:
14735118ebe8SLucas Mateus Castro (alqotel)         if (ppc64_v3_radix(cpu)) {
14745118ebe8SLucas Mateus Castro (alqotel)             return ppc_radix64_xlate(cpu, eaddr, access_type, raddrp,
14755118ebe8SLucas Mateus Castro (alqotel)                                      psizep, protp, mmu_idx, guest_visible);
14765118ebe8SLucas Mateus Castro (alqotel)         }
14775118ebe8SLucas Mateus Castro (alqotel)         /* fall through */
14785118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_64B:
14795118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_03:
14805118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_06:
14815118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_07:
14825118ebe8SLucas Mateus Castro (alqotel)         return ppc_hash64_xlate(cpu, eaddr, access_type,
14835118ebe8SLucas Mateus Castro (alqotel)                                 raddrp, psizep, protp, mmu_idx, guest_visible);
14845118ebe8SLucas Mateus Castro (alqotel) #endif
14855118ebe8SLucas Mateus Castro (alqotel) 
14865118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_32B:
14875118ebe8SLucas Mateus Castro (alqotel)         return ppc_hash32_xlate(cpu, eaddr, access_type, raddrp,
14885118ebe8SLucas Mateus Castro (alqotel)                                psizep, protp, mmu_idx, guest_visible);
1489ba91e5d0SBALATON Zoltan     case POWERPC_MMU_BOOKE:
1490ba91e5d0SBALATON Zoltan     case POWERPC_MMU_BOOKE206:
1491ba91e5d0SBALATON Zoltan         return ppc_booke_xlate(cpu, eaddr, access_type, raddrp,
1492ba91e5d0SBALATON Zoltan                                psizep, protp, mmu_idx, guest_visible);
149358b01325SBALATON Zoltan     case POWERPC_MMU_SOFT_4xx:
149458b01325SBALATON Zoltan         return ppc_40x_xlate(cpu, eaddr, access_type, raddrp,
149558b01325SBALATON Zoltan                              psizep, protp, mmu_idx, guest_visible);
14966b9ea7f3SBALATON Zoltan     case POWERPC_MMU_SOFT_6xx:
14976b9ea7f3SBALATON Zoltan         return ppc_6xx_xlate(cpu, eaddr, access_type, raddrp,
14986b9ea7f3SBALATON Zoltan                              psizep, protp, mmu_idx, guest_visible);
1499c29f808aSBALATON Zoltan     case POWERPC_MMU_REAL:
1500c29f808aSBALATON Zoltan         return ppc_real_mode_xlate(cpu, eaddr, access_type, raddrp, psizep,
1501c29f808aSBALATON Zoltan                                    protp);
1502cfd5c128SBALATON Zoltan     case POWERPC_MMU_MPC8xx:
1503cfd5c128SBALATON Zoltan         cpu_abort(env_cpu(&cpu->env), "MPC8xx MMU model is not implemented\n");
15045118ebe8SLucas Mateus Castro (alqotel)     default:
15056b9ea7f3SBALATON Zoltan         cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
15065118ebe8SLucas Mateus Castro (alqotel)     }
15075118ebe8SLucas Mateus Castro (alqotel) }
15085118ebe8SLucas Mateus Castro (alqotel) 
15095118ebe8SLucas Mateus Castro (alqotel) hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
15105118ebe8SLucas Mateus Castro (alqotel) {
15115118ebe8SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = POWERPC_CPU(cs);
15125118ebe8SLucas Mateus Castro (alqotel)     hwaddr raddr;
15135118ebe8SLucas Mateus Castro (alqotel)     int s, p;
15145118ebe8SLucas Mateus Castro (alqotel) 
15155118ebe8SLucas Mateus Castro (alqotel)     /*
15165118ebe8SLucas Mateus Castro (alqotel)      * Some MMUs have separate TLBs for code and data. If we only
15175118ebe8SLucas Mateus Castro (alqotel)      * try an MMU_DATA_LOAD, we may not be able to read instructions
15185118ebe8SLucas Mateus Castro (alqotel)      * mapped by code TLBs, so we also try a MMU_INST_FETCH.
15195118ebe8SLucas Mateus Castro (alqotel)      */
15205118ebe8SLucas Mateus Castro (alqotel)     if (ppc_xlate(cpu, addr, MMU_DATA_LOAD, &raddr, &s, &p,
1521fb00f730SRichard Henderson                   ppc_env_mmu_index(&cpu->env, false), false) ||
15225118ebe8SLucas Mateus Castro (alqotel)         ppc_xlate(cpu, addr, MMU_INST_FETCH, &raddr, &s, &p,
1523fb00f730SRichard Henderson                   ppc_env_mmu_index(&cpu->env, true), false)) {
15245118ebe8SLucas Mateus Castro (alqotel)         return raddr & TARGET_PAGE_MASK;
15255118ebe8SLucas Mateus Castro (alqotel)     }
15265118ebe8SLucas Mateus Castro (alqotel)     return -1;
15275118ebe8SLucas Mateus Castro (alqotel) }
1528