xref: /openbmc/qemu/target/ppc/mmu_common.c (revision 58b0132553139b481a4b6ea1c597465152381f66)
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) 
39d6ae8ec6SLucas Mateus Castro (alqotel) void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
40d6ae8ec6SLucas Mateus Castro (alqotel) {
41d6ae8ec6SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = env_archcpu(env);
42d6ae8ec6SLucas Mateus Castro (alqotel)     qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
43d6ae8ec6SLucas Mateus Castro (alqotel)     assert(!cpu->env.has_hv_mode || !cpu->vhyp);
44d6ae8ec6SLucas Mateus Castro (alqotel) #if defined(TARGET_PPC64)
45d6ae8ec6SLucas Mateus Castro (alqotel)     if (mmu_is_64bit(env->mmu_model)) {
46d6ae8ec6SLucas Mateus Castro (alqotel)         target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE;
47d6ae8ec6SLucas Mateus Castro (alqotel)         target_ulong htabsize = value & SDR_64_HTABSIZE;
48d6ae8ec6SLucas Mateus Castro (alqotel) 
49d6ae8ec6SLucas Mateus Castro (alqotel)         if (value & ~sdr_mask) {
50d6ae8ec6SLucas Mateus Castro (alqotel)             qemu_log_mask(LOG_GUEST_ERROR, "Invalid bits 0x"TARGET_FMT_lx
51d6ae8ec6SLucas Mateus Castro (alqotel)                      " set in SDR1", value & ~sdr_mask);
52d6ae8ec6SLucas Mateus Castro (alqotel)             value &= sdr_mask;
53d6ae8ec6SLucas Mateus Castro (alqotel)         }
54d6ae8ec6SLucas Mateus Castro (alqotel)         if (htabsize > 28) {
55d6ae8ec6SLucas Mateus Castro (alqotel)             qemu_log_mask(LOG_GUEST_ERROR, "Invalid HTABSIZE 0x" TARGET_FMT_lx
56d6ae8ec6SLucas Mateus Castro (alqotel)                      " stored in SDR1", htabsize);
57d6ae8ec6SLucas Mateus Castro (alqotel)             return;
58d6ae8ec6SLucas Mateus Castro (alqotel)         }
59d6ae8ec6SLucas Mateus Castro (alqotel)     }
60d6ae8ec6SLucas Mateus Castro (alqotel) #endif /* defined(TARGET_PPC64) */
61d6ae8ec6SLucas Mateus Castro (alqotel)     /* FIXME: Should check for valid HTABMASK values in 32-bit case */
62d6ae8ec6SLucas Mateus Castro (alqotel)     env->spr[SPR_SDR1] = value;
63d6ae8ec6SLucas Mateus Castro (alqotel) }
64d6ae8ec6SLucas Mateus Castro (alqotel) 
655118ebe8SLucas Mateus Castro (alqotel) /*****************************************************************************/
665118ebe8SLucas Mateus Castro (alqotel) /* PowerPC MMU emulation */
675118ebe8SLucas Mateus Castro (alqotel) 
685118ebe8SLucas Mateus Castro (alqotel) static int pp_check(int key, int pp, int nx)
695118ebe8SLucas Mateus Castro (alqotel) {
705118ebe8SLucas Mateus Castro (alqotel)     int access;
715118ebe8SLucas Mateus Castro (alqotel) 
725118ebe8SLucas Mateus Castro (alqotel)     /* Compute access rights */
735118ebe8SLucas Mateus Castro (alqotel)     access = 0;
745118ebe8SLucas Mateus Castro (alqotel)     if (key == 0) {
755118ebe8SLucas Mateus Castro (alqotel)         switch (pp) {
765118ebe8SLucas Mateus Castro (alqotel)         case 0x0:
775118ebe8SLucas Mateus Castro (alqotel)         case 0x1:
785118ebe8SLucas Mateus Castro (alqotel)         case 0x2:
795118ebe8SLucas Mateus Castro (alqotel)             access |= PAGE_WRITE;
805118ebe8SLucas Mateus Castro (alqotel)             /* fall through */
815118ebe8SLucas Mateus Castro (alqotel)         case 0x3:
825118ebe8SLucas Mateus Castro (alqotel)             access |= PAGE_READ;
835118ebe8SLucas Mateus Castro (alqotel)             break;
845118ebe8SLucas Mateus Castro (alqotel)         }
855118ebe8SLucas Mateus Castro (alqotel)     } else {
865118ebe8SLucas Mateus Castro (alqotel)         switch (pp) {
875118ebe8SLucas Mateus Castro (alqotel)         case 0x0:
885118ebe8SLucas Mateus Castro (alqotel)             access = 0;
895118ebe8SLucas Mateus Castro (alqotel)             break;
905118ebe8SLucas Mateus Castro (alqotel)         case 0x1:
915118ebe8SLucas Mateus Castro (alqotel)         case 0x3:
925118ebe8SLucas Mateus Castro (alqotel)             access = PAGE_READ;
935118ebe8SLucas Mateus Castro (alqotel)             break;
945118ebe8SLucas Mateus Castro (alqotel)         case 0x2:
955118ebe8SLucas Mateus Castro (alqotel)             access = PAGE_READ | PAGE_WRITE;
965118ebe8SLucas Mateus Castro (alqotel)             break;
975118ebe8SLucas Mateus Castro (alqotel)         }
985118ebe8SLucas Mateus Castro (alqotel)     }
995118ebe8SLucas Mateus Castro (alqotel)     if (nx == 0) {
1005118ebe8SLucas Mateus Castro (alqotel)         access |= PAGE_EXEC;
1015118ebe8SLucas Mateus Castro (alqotel)     }
1025118ebe8SLucas Mateus Castro (alqotel) 
1035118ebe8SLucas Mateus Castro (alqotel)     return access;
1045118ebe8SLucas Mateus Castro (alqotel) }
1055118ebe8SLucas Mateus Castro (alqotel) 
1065118ebe8SLucas Mateus Castro (alqotel) static int check_prot(int prot, MMUAccessType access_type)
1075118ebe8SLucas Mateus Castro (alqotel) {
1085118ebe8SLucas Mateus Castro (alqotel)     return prot & prot_for_access_type(access_type) ? 0 : -2;
1095118ebe8SLucas Mateus Castro (alqotel) }
1105118ebe8SLucas Mateus Castro (alqotel) 
1115118ebe8SLucas Mateus Castro (alqotel) int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
1125118ebe8SLucas Mateus Castro (alqotel)                                     int way, int is_code)
1135118ebe8SLucas Mateus Castro (alqotel) {
1145118ebe8SLucas Mateus Castro (alqotel)     int nr;
1155118ebe8SLucas Mateus Castro (alqotel) 
1165118ebe8SLucas Mateus Castro (alqotel)     /* Select TLB num in a way from address */
1175118ebe8SLucas Mateus Castro (alqotel)     nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
1185118ebe8SLucas Mateus Castro (alqotel)     /* Select TLB way */
1195118ebe8SLucas Mateus Castro (alqotel)     nr += env->tlb_per_way * way;
1205118ebe8SLucas Mateus Castro (alqotel)     /* 6xx have separate TLBs for instructions and data */
1215118ebe8SLucas Mateus Castro (alqotel)     if (is_code && env->id_tlbs == 1) {
1225118ebe8SLucas Mateus Castro (alqotel)         nr += env->nb_tlb;
1235118ebe8SLucas Mateus Castro (alqotel)     }
1245118ebe8SLucas Mateus Castro (alqotel) 
1255118ebe8SLucas Mateus Castro (alqotel)     return nr;
1265118ebe8SLucas Mateus Castro (alqotel) }
1275118ebe8SLucas Mateus Castro (alqotel) 
1285118ebe8SLucas Mateus Castro (alqotel) static int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
1295118ebe8SLucas Mateus Castro (alqotel)                                 target_ulong pte1, int h,
1305118ebe8SLucas Mateus Castro (alqotel)                                 MMUAccessType access_type)
1315118ebe8SLucas Mateus Castro (alqotel) {
1325118ebe8SLucas Mateus Castro (alqotel)     target_ulong ptem, mmask;
1335118ebe8SLucas Mateus Castro (alqotel)     int access, ret, pteh, ptev, pp;
1345118ebe8SLucas Mateus Castro (alqotel) 
1355118ebe8SLucas Mateus Castro (alqotel)     ret = -1;
1365118ebe8SLucas Mateus Castro (alqotel)     /* Check validity and table match */
1375118ebe8SLucas Mateus Castro (alqotel)     ptev = pte_is_valid(pte0);
1385118ebe8SLucas Mateus Castro (alqotel)     pteh = (pte0 >> 6) & 1;
1395118ebe8SLucas Mateus Castro (alqotel)     if (ptev && h == pteh) {
1405118ebe8SLucas Mateus Castro (alqotel)         /* Check vsid & api */
1415118ebe8SLucas Mateus Castro (alqotel)         ptem = pte0 & PTE_PTEM_MASK;
1425118ebe8SLucas Mateus Castro (alqotel)         mmask = PTE_CHECK_MASK;
1435118ebe8SLucas Mateus Castro (alqotel)         pp = pte1 & 0x00000003;
1445118ebe8SLucas Mateus Castro (alqotel)         if (ptem == ctx->ptem) {
1455118ebe8SLucas Mateus Castro (alqotel)             if (ctx->raddr != (hwaddr)-1ULL) {
1465118ebe8SLucas Mateus Castro (alqotel)                 /* all matches should have equal RPN, WIMG & PP */
1475118ebe8SLucas Mateus Castro (alqotel)                 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
1485118ebe8SLucas Mateus Castro (alqotel)                     qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
1495118ebe8SLucas Mateus Castro (alqotel)                     return -3;
1505118ebe8SLucas Mateus Castro (alqotel)                 }
1515118ebe8SLucas Mateus Castro (alqotel)             }
1525118ebe8SLucas Mateus Castro (alqotel)             /* Compute access rights */
1535118ebe8SLucas Mateus Castro (alqotel)             access = pp_check(ctx->key, pp, ctx->nx);
1545118ebe8SLucas Mateus Castro (alqotel)             /* Keep the matching PTE information */
1555118ebe8SLucas Mateus Castro (alqotel)             ctx->raddr = pte1;
1565118ebe8SLucas Mateus Castro (alqotel)             ctx->prot = access;
1575118ebe8SLucas Mateus Castro (alqotel)             ret = check_prot(ctx->prot, access_type);
1585118ebe8SLucas Mateus Castro (alqotel)             if (ret == 0) {
1595118ebe8SLucas Mateus Castro (alqotel)                 /* Access granted */
1605118ebe8SLucas Mateus Castro (alqotel)                 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
1615118ebe8SLucas Mateus Castro (alqotel)             } else {
1625118ebe8SLucas Mateus Castro (alqotel)                 /* Access right violation */
1635118ebe8SLucas Mateus Castro (alqotel)                 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
1645118ebe8SLucas Mateus Castro (alqotel)             }
1655118ebe8SLucas Mateus Castro (alqotel)         }
1665118ebe8SLucas Mateus Castro (alqotel)     }
1675118ebe8SLucas Mateus Castro (alqotel) 
1685118ebe8SLucas Mateus Castro (alqotel)     return ret;
1695118ebe8SLucas Mateus Castro (alqotel) }
1705118ebe8SLucas Mateus Castro (alqotel) 
1715118ebe8SLucas Mateus Castro (alqotel) static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
1725118ebe8SLucas Mateus Castro (alqotel)                             int ret, MMUAccessType access_type)
1735118ebe8SLucas Mateus Castro (alqotel) {
1745118ebe8SLucas Mateus Castro (alqotel)     int store = 0;
1755118ebe8SLucas Mateus Castro (alqotel) 
1765118ebe8SLucas Mateus Castro (alqotel)     /* Update page flags */
1775118ebe8SLucas Mateus Castro (alqotel)     if (!(*pte1p & 0x00000100)) {
1785118ebe8SLucas Mateus Castro (alqotel)         /* Update accessed flag */
1795118ebe8SLucas Mateus Castro (alqotel)         *pte1p |= 0x00000100;
1805118ebe8SLucas Mateus Castro (alqotel)         store = 1;
1815118ebe8SLucas Mateus Castro (alqotel)     }
1825118ebe8SLucas Mateus Castro (alqotel)     if (!(*pte1p & 0x00000080)) {
1835118ebe8SLucas Mateus Castro (alqotel)         if (access_type == MMU_DATA_STORE && ret == 0) {
1845118ebe8SLucas Mateus Castro (alqotel)             /* Update changed flag */
1855118ebe8SLucas Mateus Castro (alqotel)             *pte1p |= 0x00000080;
1865118ebe8SLucas Mateus Castro (alqotel)             store = 1;
1875118ebe8SLucas Mateus Castro (alqotel)         } else {
1885118ebe8SLucas Mateus Castro (alqotel)             /* Force page fault for first write access */
1895118ebe8SLucas Mateus Castro (alqotel)             ctx->prot &= ~PAGE_WRITE;
1905118ebe8SLucas Mateus Castro (alqotel)         }
1915118ebe8SLucas Mateus Castro (alqotel)     }
1925118ebe8SLucas Mateus Castro (alqotel) 
1935118ebe8SLucas Mateus Castro (alqotel)     return store;
1945118ebe8SLucas Mateus Castro (alqotel) }
1955118ebe8SLucas Mateus Castro (alqotel) 
1965118ebe8SLucas Mateus Castro (alqotel) /* Software driven TLB helpers */
1975118ebe8SLucas Mateus Castro (alqotel) 
1985118ebe8SLucas Mateus Castro (alqotel) static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
1995118ebe8SLucas Mateus Castro (alqotel)                             target_ulong eaddr, MMUAccessType access_type)
2005118ebe8SLucas Mateus Castro (alqotel) {
2015118ebe8SLucas Mateus Castro (alqotel)     ppc6xx_tlb_t *tlb;
2025118ebe8SLucas Mateus Castro (alqotel)     int nr, best, way;
2035118ebe8SLucas Mateus Castro (alqotel)     int ret;
2045118ebe8SLucas Mateus Castro (alqotel) 
2055118ebe8SLucas Mateus Castro (alqotel)     best = -1;
2065118ebe8SLucas Mateus Castro (alqotel)     ret = -1; /* No TLB found */
2075118ebe8SLucas Mateus Castro (alqotel)     for (way = 0; way < env->nb_ways; way++) {
2085118ebe8SLucas Mateus Castro (alqotel)         nr = ppc6xx_tlb_getnum(env, eaddr, way, access_type == MMU_INST_FETCH);
2095118ebe8SLucas Mateus Castro (alqotel)         tlb = &env->tlb.tlb6[nr];
2105118ebe8SLucas Mateus Castro (alqotel)         /* This test "emulates" the PTE index match for hardware TLBs */
2115118ebe8SLucas Mateus Castro (alqotel)         if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
21256964585SCédric Le Goater             qemu_log_mask(CPU_LOG_MMU, "TLB %d/%d %s [" TARGET_FMT_lx
21356964585SCédric Le Goater                           " " TARGET_FMT_lx "] <> " TARGET_FMT_lx "\n",
21456964585SCédric Le Goater                           nr, env->nb_tlb,
2155118ebe8SLucas Mateus Castro (alqotel)                           pte_is_valid(tlb->pte0) ? "valid" : "inval",
2165118ebe8SLucas Mateus Castro (alqotel)                           tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
2175118ebe8SLucas Mateus Castro (alqotel)             continue;
2185118ebe8SLucas Mateus Castro (alqotel)         }
21956964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "TLB %d/%d %s " TARGET_FMT_lx " <> "
22056964585SCédric Le Goater                       TARGET_FMT_lx " " TARGET_FMT_lx " %c %c\n",
22156964585SCédric Le Goater                       nr, env->nb_tlb,
2225118ebe8SLucas Mateus Castro (alqotel)                       pte_is_valid(tlb->pte0) ? "valid" : "inval",
2235118ebe8SLucas Mateus Castro (alqotel)                       tlb->EPN, eaddr, tlb->pte1,
2245118ebe8SLucas Mateus Castro (alqotel)                       access_type == MMU_DATA_STORE ? 'S' : 'L',
2255118ebe8SLucas Mateus Castro (alqotel)                       access_type == MMU_INST_FETCH ? 'I' : 'D');
2265118ebe8SLucas Mateus Castro (alqotel)         switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1,
2275118ebe8SLucas Mateus Castro (alqotel)                                      0, access_type)) {
2285118ebe8SLucas Mateus Castro (alqotel)         case -2:
2295118ebe8SLucas Mateus Castro (alqotel)             /* Access violation */
2305118ebe8SLucas Mateus Castro (alqotel)             ret = -2;
2315118ebe8SLucas Mateus Castro (alqotel)             best = nr;
2325118ebe8SLucas Mateus Castro (alqotel)             break;
2330af20f35SBALATON Zoltan         case -1: /* No match */
2340af20f35SBALATON Zoltan         case -3: /* TLB inconsistency */
2355118ebe8SLucas Mateus Castro (alqotel)         default:
2365118ebe8SLucas Mateus Castro (alqotel)             break;
2375118ebe8SLucas Mateus Castro (alqotel)         case 0:
2385118ebe8SLucas Mateus Castro (alqotel)             /* access granted */
2395118ebe8SLucas Mateus Castro (alqotel)             /*
2405118ebe8SLucas Mateus Castro (alqotel)              * XXX: we should go on looping to check all TLBs
2415118ebe8SLucas Mateus Castro (alqotel)              *      consistency but we can speed-up the whole thing as
2425118ebe8SLucas Mateus Castro (alqotel)              *      the result would be undefined if TLBs are not
2435118ebe8SLucas Mateus Castro (alqotel)              *      consistent.
2445118ebe8SLucas Mateus Castro (alqotel)              */
2455118ebe8SLucas Mateus Castro (alqotel)             ret = 0;
2465118ebe8SLucas Mateus Castro (alqotel)             best = nr;
2475118ebe8SLucas Mateus Castro (alqotel)             goto done;
2485118ebe8SLucas Mateus Castro (alqotel)         }
2495118ebe8SLucas Mateus Castro (alqotel)     }
2505118ebe8SLucas Mateus Castro (alqotel)     if (best != -1) {
2515118ebe8SLucas Mateus Castro (alqotel) done:
252883f2c59SPhilippe Mathieu-Daudé         qemu_log_mask(CPU_LOG_MMU, "found TLB at addr " HWADDR_FMT_plx
25356964585SCédric Le Goater                       " prot=%01x ret=%d\n",
2545118ebe8SLucas Mateus Castro (alqotel)                       ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
2555118ebe8SLucas Mateus Castro (alqotel)         /* Update page flags */
2565118ebe8SLucas Mateus Castro (alqotel)         pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, access_type);
2575118ebe8SLucas Mateus Castro (alqotel)     }
2580af20f35SBALATON Zoltan #if defined(DUMP_PAGE_TABLES)
2590af20f35SBALATON Zoltan     if (qemu_loglevel_mask(CPU_LOG_MMU)) {
2600af20f35SBALATON Zoltan         CPUState *cs = env_cpu(env);
2610af20f35SBALATON Zoltan         hwaddr base = ppc_hash32_hpt_base(env_archcpu(env));
2620af20f35SBALATON Zoltan         hwaddr len = ppc_hash32_hpt_mask(env_archcpu(env)) + 0x80;
2630af20f35SBALATON Zoltan         uint32_t a0, a1, a2, a3;
2645118ebe8SLucas Mateus Castro (alqotel) 
2650af20f35SBALATON Zoltan         qemu_log("Page table: " HWADDR_FMT_plx " len " HWADDR_FMT_plx "\n",
2660af20f35SBALATON Zoltan                  base, len);
2670af20f35SBALATON Zoltan         for (hwaddr curaddr = base; curaddr < base + len; curaddr += 16) {
2680af20f35SBALATON Zoltan             a0 = ldl_phys(cs->as, curaddr);
2690af20f35SBALATON Zoltan             a1 = ldl_phys(cs->as, curaddr + 4);
2700af20f35SBALATON Zoltan             a2 = ldl_phys(cs->as, curaddr + 8);
2710af20f35SBALATON Zoltan             a3 = ldl_phys(cs->as, curaddr + 12);
2720af20f35SBALATON Zoltan             if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
2730af20f35SBALATON Zoltan                 qemu_log(HWADDR_FMT_plx ": %08x %08x %08x %08x\n",
2740af20f35SBALATON Zoltan                          curaddr, a0, a1, a2, a3);
2750af20f35SBALATON Zoltan             }
2760af20f35SBALATON Zoltan         }
2770af20f35SBALATON Zoltan     }
2780af20f35SBALATON Zoltan #endif
2795118ebe8SLucas Mateus Castro (alqotel)     return ret;
2805118ebe8SLucas Mateus Castro (alqotel) }
2815118ebe8SLucas Mateus Castro (alqotel) 
2825118ebe8SLucas Mateus Castro (alqotel) /* Perform BAT hit & translation */
2835118ebe8SLucas Mateus Castro (alqotel) static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
2845118ebe8SLucas Mateus Castro (alqotel)                                  int *validp, int *protp, target_ulong *BATu,
2855118ebe8SLucas Mateus Castro (alqotel)                                  target_ulong *BATl)
2865118ebe8SLucas Mateus Castro (alqotel) {
2875118ebe8SLucas Mateus Castro (alqotel)     target_ulong bl;
2885118ebe8SLucas Mateus Castro (alqotel)     int pp, valid, prot;
2895118ebe8SLucas Mateus Castro (alqotel) 
2905118ebe8SLucas Mateus Castro (alqotel)     bl = (*BATu & 0x00001FFC) << 15;
2915118ebe8SLucas Mateus Castro (alqotel)     valid = 0;
2925118ebe8SLucas Mateus Castro (alqotel)     prot = 0;
293d41ccf6eSVíctor Colombo     if ((!FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000002)) ||
294d41ccf6eSVíctor Colombo         (FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000001))) {
2955118ebe8SLucas Mateus Castro (alqotel)         valid = 1;
2965118ebe8SLucas Mateus Castro (alqotel)         pp = *BATl & 0x00000003;
2975118ebe8SLucas Mateus Castro (alqotel)         if (pp != 0) {
2985118ebe8SLucas Mateus Castro (alqotel)             prot = PAGE_READ | PAGE_EXEC;
2995118ebe8SLucas Mateus Castro (alqotel)             if (pp == 0x2) {
3005118ebe8SLucas Mateus Castro (alqotel)                 prot |= PAGE_WRITE;
3015118ebe8SLucas Mateus Castro (alqotel)             }
3025118ebe8SLucas Mateus Castro (alqotel)         }
3035118ebe8SLucas Mateus Castro (alqotel)     }
3045118ebe8SLucas Mateus Castro (alqotel)     *blp = bl;
3055118ebe8SLucas Mateus Castro (alqotel)     *validp = valid;
3065118ebe8SLucas Mateus Castro (alqotel)     *protp = prot;
3075118ebe8SLucas Mateus Castro (alqotel) }
3085118ebe8SLucas Mateus Castro (alqotel) 
3095118ebe8SLucas Mateus Castro (alqotel) static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
3105118ebe8SLucas Mateus Castro (alqotel)                            target_ulong virtual, MMUAccessType access_type)
3115118ebe8SLucas Mateus Castro (alqotel) {
3125118ebe8SLucas Mateus Castro (alqotel)     target_ulong *BATlt, *BATut, *BATu, *BATl;
3135118ebe8SLucas Mateus Castro (alqotel)     target_ulong BEPIl, BEPIu, bl;
3145118ebe8SLucas Mateus Castro (alqotel)     int i, valid, prot;
3155118ebe8SLucas Mateus Castro (alqotel)     int ret = -1;
3165118ebe8SLucas Mateus Castro (alqotel)     bool ifetch = access_type == MMU_INST_FETCH;
3175118ebe8SLucas Mateus Castro (alqotel) 
31856964585SCédric Le Goater     qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
3195118ebe8SLucas Mateus Castro (alqotel)                   ifetch ? 'I' : 'D', virtual);
3205118ebe8SLucas Mateus Castro (alqotel)     if (ifetch) {
3215118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->IBAT[1];
3225118ebe8SLucas Mateus Castro (alqotel)         BATut = env->IBAT[0];
3235118ebe8SLucas Mateus Castro (alqotel)     } else {
3245118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->DBAT[1];
3255118ebe8SLucas Mateus Castro (alqotel)         BATut = env->DBAT[0];
3265118ebe8SLucas Mateus Castro (alqotel)     }
3275118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_BATs; i++) {
3285118ebe8SLucas Mateus Castro (alqotel)         BATu = &BATut[i];
3295118ebe8SLucas Mateus Castro (alqotel)         BATl = &BATlt[i];
3305118ebe8SLucas Mateus Castro (alqotel)         BEPIu = *BATu & 0xF0000000;
3315118ebe8SLucas Mateus Castro (alqotel)         BEPIl = *BATu & 0x0FFE0000;
3325118ebe8SLucas Mateus Castro (alqotel)         bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
33356964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx " BATu "
33456964585SCédric Le Goater                       TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n", __func__,
3355118ebe8SLucas Mateus Castro (alqotel)                       ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl);
3365118ebe8SLucas Mateus Castro (alqotel)         if ((virtual & 0xF0000000) == BEPIu &&
3375118ebe8SLucas Mateus Castro (alqotel)             ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
3385118ebe8SLucas Mateus Castro (alqotel)             /* BAT matches */
3395118ebe8SLucas Mateus Castro (alqotel)             if (valid != 0) {
3405118ebe8SLucas Mateus Castro (alqotel)                 /* Get physical address */
3415118ebe8SLucas Mateus Castro (alqotel)                 ctx->raddr = (*BATl & 0xF0000000) |
3425118ebe8SLucas Mateus Castro (alqotel)                     ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
3435118ebe8SLucas Mateus Castro (alqotel)                     (virtual & 0x0001F000);
3445118ebe8SLucas Mateus Castro (alqotel)                 /* Compute access rights */
3455118ebe8SLucas Mateus Castro (alqotel)                 ctx->prot = prot;
3465118ebe8SLucas Mateus Castro (alqotel)                 ret = check_prot(ctx->prot, access_type);
3475118ebe8SLucas Mateus Castro (alqotel)                 if (ret == 0) {
348883f2c59SPhilippe Mathieu-Daudé                     qemu_log_mask(CPU_LOG_MMU, "BAT %d match: r " HWADDR_FMT_plx
34956964585SCédric Le Goater                                   " prot=%c%c\n", i, ctx->raddr,
35056964585SCédric Le Goater                                   ctx->prot & PAGE_READ ? 'R' : '-',
3515118ebe8SLucas Mateus Castro (alqotel)                                   ctx->prot & PAGE_WRITE ? 'W' : '-');
3525118ebe8SLucas Mateus Castro (alqotel)                 }
3535118ebe8SLucas Mateus Castro (alqotel)                 break;
3545118ebe8SLucas Mateus Castro (alqotel)             }
3555118ebe8SLucas Mateus Castro (alqotel)         }
3565118ebe8SLucas Mateus Castro (alqotel)     }
3575118ebe8SLucas Mateus Castro (alqotel)     if (ret < 0) {
3585118ebe8SLucas Mateus Castro (alqotel)         if (qemu_log_enabled()) {
35956964585SCédric Le Goater             qemu_log_mask(CPU_LOG_MMU, "no BAT match for "
36056964585SCédric Le Goater                           TARGET_FMT_lx ":\n", virtual);
3615118ebe8SLucas Mateus Castro (alqotel)             for (i = 0; i < 4; i++) {
3625118ebe8SLucas Mateus Castro (alqotel)                 BATu = &BATut[i];
3635118ebe8SLucas Mateus Castro (alqotel)                 BATl = &BATlt[i];
3645118ebe8SLucas Mateus Castro (alqotel)                 BEPIu = *BATu & 0xF0000000;
3655118ebe8SLucas Mateus Castro (alqotel)                 BEPIl = *BATu & 0x0FFE0000;
3665118ebe8SLucas Mateus Castro (alqotel)                 bl = (*BATu & 0x00001FFC) << 15;
36747bededcSBALATON Zoltan                 qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx
36847bededcSBALATON Zoltan                               " BATu " TARGET_FMT_lx " BATl " TARGET_FMT_lx
36947bededcSBALATON Zoltan                               "\n\t" TARGET_FMT_lx " " TARGET_FMT_lx " "
37047bededcSBALATON Zoltan                               TARGET_FMT_lx "\n", __func__, ifetch ? 'I' : 'D',
37147bededcSBALATON Zoltan                               i, virtual, *BATu, *BATl, BEPIu, BEPIl, bl);
3725118ebe8SLucas Mateus Castro (alqotel)             }
3735118ebe8SLucas Mateus Castro (alqotel)         }
3745118ebe8SLucas Mateus Castro (alqotel)     }
3755118ebe8SLucas Mateus Castro (alqotel)     /* No hit */
3765118ebe8SLucas Mateus Castro (alqotel)     return ret;
3775118ebe8SLucas Mateus Castro (alqotel) }
3785118ebe8SLucas Mateus Castro (alqotel) 
379269d6f00SBALATON Zoltan static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
380269d6f00SBALATON Zoltan                                        target_ulong eaddr,
381269d6f00SBALATON Zoltan                                        MMUAccessType access_type, int type)
3825118ebe8SLucas Mateus Castro (alqotel) {
3835118ebe8SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = env_archcpu(env);
3845118ebe8SLucas Mateus Castro (alqotel)     hwaddr hash;
385269d6f00SBALATON Zoltan     target_ulong vsid, sr, pgidx;
386d41ccf6eSVíctor Colombo     int ds, target_page_bits;
387d41ccf6eSVíctor Colombo     bool pr;
3885118ebe8SLucas Mateus Castro (alqotel) 
389269d6f00SBALATON Zoltan     /* First try to find a BAT entry if there are any */
390269d6f00SBALATON Zoltan     if (env->nb_BATs && get_bat_6xx_tlb(env, ctx, eaddr, access_type) == 0) {
391269d6f00SBALATON Zoltan         return 0;
392269d6f00SBALATON Zoltan     }
393269d6f00SBALATON Zoltan 
394269d6f00SBALATON Zoltan     /* Perform segment based translation when no BATs matched */
395d41ccf6eSVíctor Colombo     pr = FIELD_EX64(env->msr, MSR, PR);
3965118ebe8SLucas Mateus Castro (alqotel)     ctx->eaddr = eaddr;
3975118ebe8SLucas Mateus Castro (alqotel) 
3985118ebe8SLucas Mateus Castro (alqotel)     sr = env->sr[eaddr >> 28];
399d41ccf6eSVíctor Colombo     ctx->key = (((sr & 0x20000000) && pr) ||
400d41ccf6eSVíctor Colombo                 ((sr & 0x40000000) && !pr)) ? 1 : 0;
4015118ebe8SLucas Mateus Castro (alqotel)     ds = sr & 0x80000000 ? 1 : 0;
4025118ebe8SLucas Mateus Castro (alqotel)     ctx->nx = sr & 0x10000000 ? 1 : 0;
4035118ebe8SLucas Mateus Castro (alqotel)     vsid = sr & 0x00FFFFFF;
4045118ebe8SLucas Mateus Castro (alqotel)     target_page_bits = TARGET_PAGE_BITS;
4055118ebe8SLucas Mateus Castro (alqotel)     qemu_log_mask(CPU_LOG_MMU,
4065118ebe8SLucas Mateus Castro (alqotel)                   "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
4075118ebe8SLucas Mateus Castro (alqotel)                   " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
4085118ebe8SLucas Mateus Castro (alqotel)                   " ir=%d dr=%d pr=%d %d t=%d\n",
409d41ccf6eSVíctor Colombo                   eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr,
410e4eea6efSVíctor Colombo                   (int)FIELD_EX64(env->msr, MSR, IR),
411e4eea6efSVíctor Colombo                   (int)FIELD_EX64(env->msr, MSR, DR), pr ? 1 : 0,
41256964585SCédric Le Goater                   access_type == MMU_DATA_STORE, type);
4135118ebe8SLucas Mateus Castro (alqotel)     pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
4145118ebe8SLucas Mateus Castro (alqotel)     hash = vsid ^ pgidx;
4155118ebe8SLucas Mateus Castro (alqotel)     ctx->ptem = (vsid << 7) | (pgidx >> 10);
4165118ebe8SLucas Mateus Castro (alqotel) 
41747bededcSBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "pte segment: key=%d ds %d nx %d vsid "
41847bededcSBALATON Zoltan                   TARGET_FMT_lx "\n", ctx->key, ds, ctx->nx, vsid);
4195118ebe8SLucas Mateus Castro (alqotel)     if (!ds) {
4205118ebe8SLucas Mateus Castro (alqotel)         /* Check if instruction fetch is allowed, if needed */
421f1418bdeSBALATON Zoltan         if (type == ACCESS_CODE && ctx->nx) {
422f1418bdeSBALATON Zoltan             qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
423f1418bdeSBALATON Zoltan             return -3;
424f1418bdeSBALATON Zoltan         }
4255118ebe8SLucas Mateus Castro (alqotel)         /* Page address translation */
426f1418bdeSBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx " htab_mask "
427f1418bdeSBALATON Zoltan                       HWADDR_FMT_plx " hash " HWADDR_FMT_plx "\n",
4285118ebe8SLucas Mateus Castro (alqotel)                       ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
4295118ebe8SLucas Mateus Castro (alqotel)         ctx->hash[0] = hash;
4305118ebe8SLucas Mateus Castro (alqotel)         ctx->hash[1] = ~hash;
4315118ebe8SLucas Mateus Castro (alqotel) 
4325118ebe8SLucas Mateus Castro (alqotel)         /* Initialize real address with an invalid value */
4335118ebe8SLucas Mateus Castro (alqotel)         ctx->raddr = (hwaddr)-1ULL;
4345118ebe8SLucas Mateus Castro (alqotel)         /* Software TLB search */
435f3f66a31SBALATON Zoltan         return ppc6xx_tlb_check(env, ctx, eaddr, access_type);
436f3f66a31SBALATON Zoltan     }
4375118ebe8SLucas Mateus Castro (alqotel) 
438f3f66a31SBALATON Zoltan     /* Direct-store segment : absolutely *BUGGY* for now */
439f3f66a31SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
4405118ebe8SLucas Mateus Castro (alqotel)     switch (type) {
4415118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_INT:
4425118ebe8SLucas Mateus Castro (alqotel)         /* Integer load/store : only access allowed */
4435118ebe8SLucas Mateus Castro (alqotel)         break;
4445118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_CODE:
4455118ebe8SLucas Mateus Castro (alqotel)         /* No code fetch is allowed in direct-store areas */
4465118ebe8SLucas Mateus Castro (alqotel)         return -4;
4475118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_FLOAT:
4485118ebe8SLucas Mateus Castro (alqotel)         /* Floating point load/store */
4495118ebe8SLucas Mateus Castro (alqotel)         return -4;
4505118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_RES:
4515118ebe8SLucas Mateus Castro (alqotel)         /* lwarx, ldarx or srwcx. */
4525118ebe8SLucas Mateus Castro (alqotel)         return -4;
4535118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_CACHE:
4545118ebe8SLucas Mateus Castro (alqotel)         /*
4555118ebe8SLucas Mateus Castro (alqotel)          * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
4565118ebe8SLucas Mateus Castro (alqotel)          *
4575118ebe8SLucas Mateus Castro (alqotel)          * Should make the instruction do no-op.  As it already do
4585118ebe8SLucas Mateus Castro (alqotel)          * no-op, it's quite easy :-)
4595118ebe8SLucas Mateus Castro (alqotel)          */
4605118ebe8SLucas Mateus Castro (alqotel)         ctx->raddr = eaddr;
4615118ebe8SLucas Mateus Castro (alqotel)         return 0;
4625118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_EXT:
4635118ebe8SLucas Mateus Castro (alqotel)         /* eciwx or ecowx */
4645118ebe8SLucas Mateus Castro (alqotel)         return -4;
4655118ebe8SLucas Mateus Castro (alqotel)     default:
466f3f66a31SBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need address"
467f3f66a31SBALATON Zoltan                                    " translation\n");
4685118ebe8SLucas Mateus Castro (alqotel)         return -4;
4695118ebe8SLucas Mateus Castro (alqotel)     }
4705118ebe8SLucas Mateus Castro (alqotel)     if ((access_type == MMU_DATA_STORE || ctx->key != 1) &&
4715118ebe8SLucas Mateus Castro (alqotel)         (access_type == MMU_DATA_LOAD || ctx->key != 0)) {
4725118ebe8SLucas Mateus Castro (alqotel)         ctx->raddr = eaddr;
473f3f66a31SBALATON Zoltan         return 2;
4745118ebe8SLucas Mateus Castro (alqotel)     }
475f3f66a31SBALATON Zoltan     return -2;
4765118ebe8SLucas Mateus Castro (alqotel) }
4775118ebe8SLucas Mateus Castro (alqotel) 
4785118ebe8SLucas Mateus Castro (alqotel) /* Generic TLB check function for embedded PowerPC implementations */
4792b23daa8SBALATON Zoltan static bool ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
4805118ebe8SLucas Mateus Castro (alqotel)                              hwaddr *raddrp,
48162860c5fSBALATON Zoltan                              target_ulong address, uint32_t pid, int i)
4825118ebe8SLucas Mateus Castro (alqotel) {
4835118ebe8SLucas Mateus Castro (alqotel)     target_ulong mask;
4845118ebe8SLucas Mateus Castro (alqotel) 
4855118ebe8SLucas Mateus Castro (alqotel)     /* Check valid flag */
4865118ebe8SLucas Mateus Castro (alqotel)     if (!(tlb->prot & PAGE_VALID)) {
4872b23daa8SBALATON Zoltan         return false;
4885118ebe8SLucas Mateus Castro (alqotel)     }
4895118ebe8SLucas Mateus Castro (alqotel)     mask = ~(tlb->size - 1);
49056964585SCédric Le Goater     qemu_log_mask(CPU_LOG_MMU, "%s: TLB %d address " TARGET_FMT_lx
49156964585SCédric Le Goater                   " PID %u <=> " TARGET_FMT_lx " " TARGET_FMT_lx " %u %x\n",
49256964585SCédric Le Goater                   __func__, i, address, pid, tlb->EPN,
4935118ebe8SLucas Mateus Castro (alqotel)                   mask, (uint32_t)tlb->PID, tlb->prot);
4945118ebe8SLucas Mateus Castro (alqotel)     /* Check PID */
4955118ebe8SLucas Mateus Castro (alqotel)     if (tlb->PID != 0 && tlb->PID != pid) {
4962b23daa8SBALATON Zoltan         return false;
4975118ebe8SLucas Mateus Castro (alqotel)     }
4985118ebe8SLucas Mateus Castro (alqotel)     /* Check effective address */
4995118ebe8SLucas Mateus Castro (alqotel)     if ((address & mask) != tlb->EPN) {
5002b23daa8SBALATON Zoltan         return false;
5015118ebe8SLucas Mateus Castro (alqotel)     }
5025118ebe8SLucas Mateus Castro (alqotel)     *raddrp = (tlb->RPN & mask) | (address & ~mask);
5032b23daa8SBALATON Zoltan     return true;
5045118ebe8SLucas Mateus Castro (alqotel) }
5055118ebe8SLucas Mateus Castro (alqotel) 
506753441c8SBALATON Zoltan /* Generic TLB search function for PowerPC embedded implementations */
507753441c8SBALATON Zoltan int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid)
508753441c8SBALATON Zoltan {
509753441c8SBALATON Zoltan     ppcemb_tlb_t *tlb;
510753441c8SBALATON Zoltan     hwaddr raddr;
511bb60364cSBALATON Zoltan     int i;
512753441c8SBALATON Zoltan 
513753441c8SBALATON Zoltan     for (i = 0; i < env->nb_tlb; i++) {
514753441c8SBALATON Zoltan         tlb = &env->tlb.tlbe[i];
5152b23daa8SBALATON Zoltan         if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, i)) {
516bb60364cSBALATON Zoltan             return i;
517753441c8SBALATON Zoltan         }
518753441c8SBALATON Zoltan     }
519bb60364cSBALATON Zoltan     return -1;
520753441c8SBALATON Zoltan }
521753441c8SBALATON Zoltan 
5225cc867a6SBALATON Zoltan static int mmu40x_get_physical_address(CPUPPCState *env, hwaddr *raddr,
5235cc867a6SBALATON Zoltan                                        int *prot, target_ulong address,
5245118ebe8SLucas Mateus Castro (alqotel)                                        MMUAccessType access_type)
5255118ebe8SLucas Mateus Castro (alqotel) {
5265118ebe8SLucas Mateus Castro (alqotel)     ppcemb_tlb_t *tlb;
5275118ebe8SLucas Mateus Castro (alqotel)     int i, ret, zsel, zpr, pr;
5285118ebe8SLucas Mateus Castro (alqotel) 
5295118ebe8SLucas Mateus Castro (alqotel)     ret = -1;
530d41ccf6eSVíctor Colombo     pr = FIELD_EX64(env->msr, MSR, PR);
5315118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_tlb; i++) {
5325118ebe8SLucas Mateus Castro (alqotel)         tlb = &env->tlb.tlbe[i];
5335cc867a6SBALATON Zoltan         if (!ppcemb_tlb_check(env, tlb, raddr, address,
5342b23daa8SBALATON Zoltan                               env->spr[SPR_40x_PID], i)) {
5355118ebe8SLucas Mateus Castro (alqotel)             continue;
5365118ebe8SLucas Mateus Castro (alqotel)         }
5375118ebe8SLucas Mateus Castro (alqotel)         zsel = (tlb->attr >> 4) & 0xF;
5385118ebe8SLucas Mateus Castro (alqotel)         zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
53956964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU,
54056964585SCédric Le Goater                       "%s: TLB %d zsel %d zpr %d ty %d attr %08x\n",
5415118ebe8SLucas Mateus Castro (alqotel)                       __func__, i, zsel, zpr, access_type, tlb->attr);
5425118ebe8SLucas Mateus Castro (alqotel)         /* Check execute enable bit */
5435118ebe8SLucas Mateus Castro (alqotel)         switch (zpr) {
5445118ebe8SLucas Mateus Castro (alqotel)         case 0x2:
5455118ebe8SLucas Mateus Castro (alqotel)             if (pr != 0) {
5465118ebe8SLucas Mateus Castro (alqotel)                 goto check_perms;
5475118ebe8SLucas Mateus Castro (alqotel)             }
5485118ebe8SLucas Mateus Castro (alqotel)             /* fall through */
5495118ebe8SLucas Mateus Castro (alqotel)         case 0x3:
5505118ebe8SLucas Mateus Castro (alqotel)             /* All accesses granted */
5515cc867a6SBALATON Zoltan             *prot = PAGE_RWX;
5525118ebe8SLucas Mateus Castro (alqotel)             ret = 0;
5535118ebe8SLucas Mateus Castro (alqotel)             break;
5545cc867a6SBALATON Zoltan 
5555118ebe8SLucas Mateus Castro (alqotel)         case 0x0:
5565118ebe8SLucas Mateus Castro (alqotel)             if (pr != 0) {
5575118ebe8SLucas Mateus Castro (alqotel)                 /* Raise Zone protection fault.  */
5585118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_40x_ESR] = 1 << 22;
5595cc867a6SBALATON Zoltan                 *prot = 0;
5605118ebe8SLucas Mateus Castro (alqotel)                 ret = -2;
5615118ebe8SLucas Mateus Castro (alqotel)                 break;
5625118ebe8SLucas Mateus Castro (alqotel)             }
5635118ebe8SLucas Mateus Castro (alqotel)             /* fall through */
5645118ebe8SLucas Mateus Castro (alqotel)         case 0x1:
5655118ebe8SLucas Mateus Castro (alqotel) check_perms:
5665118ebe8SLucas Mateus Castro (alqotel)             /* Check from TLB entry */
5675cc867a6SBALATON Zoltan             *prot = tlb->prot;
5685cc867a6SBALATON Zoltan             ret = check_prot(*prot, access_type);
5695118ebe8SLucas Mateus Castro (alqotel)             if (ret == -2) {
5705118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_40x_ESR] = 0;
5715118ebe8SLucas Mateus Castro (alqotel)             }
5725118ebe8SLucas Mateus Castro (alqotel)             break;
5735118ebe8SLucas Mateus Castro (alqotel)         }
5745118ebe8SLucas Mateus Castro (alqotel)     }
5755cc867a6SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => "
5765cc867a6SBALATON Zoltan                   HWADDR_FMT_plx " %d %d\n",  __func__,
5775cc867a6SBALATON Zoltan                   ret < 0 ? "refused" : "granted", address,
5785cc867a6SBALATON Zoltan                   ret < 0 ? 0 : *raddr, *prot, ret);
5795118ebe8SLucas Mateus Castro (alqotel) 
5805118ebe8SLucas Mateus Castro (alqotel)     return ret;
5815118ebe8SLucas Mateus Castro (alqotel) }
5825118ebe8SLucas Mateus Castro (alqotel) 
583a5436bc6SBALATON Zoltan static bool mmubooke_check_pid(CPUPPCState *env, ppcemb_tlb_t *tlb,
584a5436bc6SBALATON Zoltan                                hwaddr *raddr, target_ulong addr, int i)
585a5436bc6SBALATON Zoltan {
586a5436bc6SBALATON Zoltan     if (ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID], i)) {
587a5436bc6SBALATON Zoltan         if (!env->nb_pids) {
588a5436bc6SBALATON Zoltan             /* Extend the physical address to 36 bits */
589a5436bc6SBALATON Zoltan             *raddr |= (uint64_t)(tlb->RPN & 0xF) << 32;
590a5436bc6SBALATON Zoltan         }
591a5436bc6SBALATON Zoltan         return true;
592a5436bc6SBALATON Zoltan     } else if (!env->nb_pids) {
593a5436bc6SBALATON Zoltan         return false;
594a5436bc6SBALATON Zoltan     }
595a5436bc6SBALATON Zoltan     if (env->spr[SPR_BOOKE_PID1] &&
596a5436bc6SBALATON Zoltan         ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID1], i)) {
597a5436bc6SBALATON Zoltan         return true;
598a5436bc6SBALATON Zoltan     }
599a5436bc6SBALATON Zoltan     if (env->spr[SPR_BOOKE_PID2] &&
600a5436bc6SBALATON Zoltan         ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID2], i)) {
601a5436bc6SBALATON Zoltan         return true;
602a5436bc6SBALATON Zoltan     }
603a5436bc6SBALATON Zoltan     return false;
604a5436bc6SBALATON Zoltan }
605a5436bc6SBALATON Zoltan 
6065118ebe8SLucas Mateus Castro (alqotel) static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
6075118ebe8SLucas Mateus Castro (alqotel)                               hwaddr *raddr, int *prot, target_ulong address,
6085118ebe8SLucas Mateus Castro (alqotel)                               MMUAccessType access_type, int i)
6095118ebe8SLucas Mateus Castro (alqotel) {
610a5436bc6SBALATON Zoltan     if (!mmubooke_check_pid(env, tlb, raddr, address, i)) {
61156964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: TLB entry not found\n", __func__);
6125118ebe8SLucas Mateus Castro (alqotel)         return -1;
613a5436bc6SBALATON Zoltan     }
6145118ebe8SLucas Mateus Castro (alqotel) 
6155118ebe8SLucas Mateus Castro (alqotel)     /* Check the address space */
6164d979c9fSVíctor Colombo     if ((access_type == MMU_INST_FETCH ?
617e4eea6efSVíctor Colombo         FIELD_EX64(env->msr, MSR, IR) :
618e4eea6efSVíctor Colombo         FIELD_EX64(env->msr, MSR, DR)) != (tlb->attr & 1)) {
61956964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
6205118ebe8SLucas Mateus Castro (alqotel)         return -1;
6215118ebe8SLucas Mateus Castro (alqotel)     }
6225118ebe8SLucas Mateus Castro (alqotel) 
6233f520078SBALATON Zoltan     if (FIELD_EX64(env->msr, MSR, PR)) {
624750fbe33SBALATON Zoltan         *prot = tlb->prot & 0xF;
6253f520078SBALATON Zoltan     } else {
626750fbe33SBALATON Zoltan         *prot = (tlb->prot >> 4) & 0xF;
6273f520078SBALATON Zoltan     }
628750fbe33SBALATON Zoltan     if (*prot & prot_for_access_type(access_type)) {
62956964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
6305118ebe8SLucas Mateus Castro (alqotel)         return 0;
6315118ebe8SLucas Mateus Castro (alqotel)     }
6325118ebe8SLucas Mateus Castro (alqotel) 
633750fbe33SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot);
6345118ebe8SLucas Mateus Castro (alqotel)     return access_type == MMU_INST_FETCH ? -3 : -2;
6355118ebe8SLucas Mateus Castro (alqotel) }
6365118ebe8SLucas Mateus Castro (alqotel) 
637ecff3394SBALATON Zoltan static int mmubooke_get_physical_address(CPUPPCState *env, hwaddr *raddr,
638ecff3394SBALATON Zoltan                                          int *prot, target_ulong address,
6395118ebe8SLucas Mateus Castro (alqotel)                                          MMUAccessType access_type)
6405118ebe8SLucas Mateus Castro (alqotel) {
6415118ebe8SLucas Mateus Castro (alqotel)     ppcemb_tlb_t *tlb;
642ecff3394SBALATON Zoltan     int i, ret = -1;
6435118ebe8SLucas Mateus Castro (alqotel) 
6445118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_tlb; i++) {
6455118ebe8SLucas Mateus Castro (alqotel)         tlb = &env->tlb.tlbe[i];
646ecff3394SBALATON Zoltan         ret = mmubooke_check_tlb(env, tlb, raddr, prot, address,
6475118ebe8SLucas Mateus Castro (alqotel)                                  access_type, i);
6485118ebe8SLucas Mateus Castro (alqotel)         if (ret != -1) {
6495118ebe8SLucas Mateus Castro (alqotel)             break;
6505118ebe8SLucas Mateus Castro (alqotel)         }
6515118ebe8SLucas Mateus Castro (alqotel)     }
652ecff3394SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU,
653ecff3394SBALATON Zoltan                   "%s: access %s " TARGET_FMT_lx " => " HWADDR_FMT_plx
654ecff3394SBALATON Zoltan                   " %d %d\n", __func__, ret < 0 ? "refused" : "granted",
655ecff3394SBALATON Zoltan                   address, ret < 0 ? -1 : *raddr, ret == -1 ? 0 : *prot, ret);
6565118ebe8SLucas Mateus Castro (alqotel)     return ret;
6575118ebe8SLucas Mateus Castro (alqotel) }
6585118ebe8SLucas Mateus Castro (alqotel) 
659a1fa47faSBALATON Zoltan hwaddr booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb)
6605118ebe8SLucas Mateus Castro (alqotel) {
6615118ebe8SLucas Mateus Castro (alqotel)     int tlbm_size;
6625118ebe8SLucas Mateus Castro (alqotel) 
6635118ebe8SLucas Mateus Castro (alqotel)     tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
6645118ebe8SLucas Mateus Castro (alqotel) 
6655118ebe8SLucas Mateus Castro (alqotel)     return 1024ULL << tlbm_size;
6665118ebe8SLucas Mateus Castro (alqotel) }
6675118ebe8SLucas Mateus Castro (alqotel) 
6685118ebe8SLucas Mateus Castro (alqotel) /* TLB check function for MAS based SoftTLBs */
669a1fa47faSBALATON Zoltan int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddrp,
670a1fa47faSBALATON Zoltan                      target_ulong address, uint32_t pid)
6715118ebe8SLucas Mateus Castro (alqotel) {
6725118ebe8SLucas Mateus Castro (alqotel)     hwaddr mask;
6735118ebe8SLucas Mateus Castro (alqotel)     uint32_t tlb_pid;
6745118ebe8SLucas Mateus Castro (alqotel) 
675cda23360SVíctor Colombo     if (!FIELD_EX64(env->msr, MSR, CM)) {
6765118ebe8SLucas Mateus Castro (alqotel)         /* In 32bit mode we can only address 32bit EAs */
6775118ebe8SLucas Mateus Castro (alqotel)         address = (uint32_t)address;
6785118ebe8SLucas Mateus Castro (alqotel)     }
6795118ebe8SLucas Mateus Castro (alqotel) 
6805118ebe8SLucas Mateus Castro (alqotel)     /* Check valid flag */
6815118ebe8SLucas Mateus Castro (alqotel)     if (!(tlb->mas1 & MAS1_VALID)) {
6825118ebe8SLucas Mateus Castro (alqotel)         return -1;
6835118ebe8SLucas Mateus Castro (alqotel)     }
6845118ebe8SLucas Mateus Castro (alqotel) 
6855118ebe8SLucas Mateus Castro (alqotel)     mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
68656964585SCédric Le Goater     qemu_log_mask(CPU_LOG_MMU, "%s: TLB ADDR=0x" TARGET_FMT_lx
68756964585SCédric Le Goater                   " PID=0x%x MAS1=0x%x MAS2=0x%" PRIx64 " mask=0x%"
68856964585SCédric Le Goater                   HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%" PRIx32 "\n",
68956964585SCédric Le Goater                   __func__, address, pid, tlb->mas1, tlb->mas2, mask,
6905118ebe8SLucas Mateus Castro (alqotel)                   tlb->mas7_3, tlb->mas8);
6915118ebe8SLucas Mateus Castro (alqotel) 
6925118ebe8SLucas Mateus Castro (alqotel)     /* Check PID */
6935118ebe8SLucas Mateus Castro (alqotel)     tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
6945118ebe8SLucas Mateus Castro (alqotel)     if (tlb_pid != 0 && tlb_pid != pid) {
6955118ebe8SLucas Mateus Castro (alqotel)         return -1;
6965118ebe8SLucas Mateus Castro (alqotel)     }
6975118ebe8SLucas Mateus Castro (alqotel) 
6985118ebe8SLucas Mateus Castro (alqotel)     /* Check effective address */
6995118ebe8SLucas Mateus Castro (alqotel)     if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
7005118ebe8SLucas Mateus Castro (alqotel)         return -1;
7015118ebe8SLucas Mateus Castro (alqotel)     }
7025118ebe8SLucas Mateus Castro (alqotel) 
7035118ebe8SLucas Mateus Castro (alqotel)     if (raddrp) {
7045118ebe8SLucas Mateus Castro (alqotel)         *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
7055118ebe8SLucas Mateus Castro (alqotel)     }
7065118ebe8SLucas Mateus Castro (alqotel) 
7075118ebe8SLucas Mateus Castro (alqotel)     return 0;
7085118ebe8SLucas Mateus Castro (alqotel) }
7095118ebe8SLucas Mateus Castro (alqotel) 
7105118ebe8SLucas Mateus Castro (alqotel) static bool is_epid_mmu(int mmu_idx)
7115118ebe8SLucas Mateus Castro (alqotel) {
7125118ebe8SLucas Mateus Castro (alqotel)     return mmu_idx == PPC_TLB_EPID_STORE || mmu_idx == PPC_TLB_EPID_LOAD;
7135118ebe8SLucas Mateus Castro (alqotel) }
7145118ebe8SLucas Mateus Castro (alqotel) 
7155118ebe8SLucas Mateus Castro (alqotel) static uint32_t mmubooke206_esr(int mmu_idx, MMUAccessType access_type)
7165118ebe8SLucas Mateus Castro (alqotel) {
7175118ebe8SLucas Mateus Castro (alqotel)     uint32_t esr = 0;
7185118ebe8SLucas Mateus Castro (alqotel)     if (access_type == MMU_DATA_STORE) {
7195118ebe8SLucas Mateus Castro (alqotel)         esr |= ESR_ST;
7205118ebe8SLucas Mateus Castro (alqotel)     }
7215118ebe8SLucas Mateus Castro (alqotel)     if (is_epid_mmu(mmu_idx)) {
7225118ebe8SLucas Mateus Castro (alqotel)         esr |= ESR_EPID;
7235118ebe8SLucas Mateus Castro (alqotel)     }
7245118ebe8SLucas Mateus Castro (alqotel)     return esr;
7255118ebe8SLucas Mateus Castro (alqotel) }
7265118ebe8SLucas Mateus Castro (alqotel) 
7275118ebe8SLucas Mateus Castro (alqotel) /*
7285118ebe8SLucas Mateus Castro (alqotel)  * Get EPID register given the mmu_idx. If this is regular load,
7295118ebe8SLucas Mateus Castro (alqotel)  * construct the EPID access bits from current processor state
7305118ebe8SLucas Mateus Castro (alqotel)  *
7315118ebe8SLucas Mateus Castro (alqotel)  * Get the effective AS and PR bits and the PID. The PID is returned
7325118ebe8SLucas Mateus Castro (alqotel)  * only if EPID load is requested, otherwise the caller must detect
7335118ebe8SLucas Mateus Castro (alqotel)  * the correct EPID.  Return true if valid EPID is returned.
7345118ebe8SLucas Mateus Castro (alqotel)  */
7355118ebe8SLucas Mateus Castro (alqotel) static bool mmubooke206_get_as(CPUPPCState *env,
7365118ebe8SLucas Mateus Castro (alqotel)                                int mmu_idx, uint32_t *epid_out,
7375118ebe8SLucas Mateus Castro (alqotel)                                bool *as_out, bool *pr_out)
7385118ebe8SLucas Mateus Castro (alqotel) {
7395118ebe8SLucas Mateus Castro (alqotel)     if (is_epid_mmu(mmu_idx)) {
7405118ebe8SLucas Mateus Castro (alqotel)         uint32_t epidr;
7415118ebe8SLucas Mateus Castro (alqotel)         if (mmu_idx == PPC_TLB_EPID_STORE) {
7425118ebe8SLucas Mateus Castro (alqotel)             epidr = env->spr[SPR_BOOKE_EPSC];
7435118ebe8SLucas Mateus Castro (alqotel)         } else {
7445118ebe8SLucas Mateus Castro (alqotel)             epidr = env->spr[SPR_BOOKE_EPLC];
7455118ebe8SLucas Mateus Castro (alqotel)         }
7465118ebe8SLucas Mateus Castro (alqotel)         *epid_out = (epidr & EPID_EPID) >> EPID_EPID_SHIFT;
7475118ebe8SLucas Mateus Castro (alqotel)         *as_out = !!(epidr & EPID_EAS);
7485118ebe8SLucas Mateus Castro (alqotel)         *pr_out = !!(epidr & EPID_EPR);
7495118ebe8SLucas Mateus Castro (alqotel)         return true;
7505118ebe8SLucas Mateus Castro (alqotel)     } else {
75126363616SVíctor Colombo         *as_out = FIELD_EX64(env->msr, MSR, DS);
752d41ccf6eSVíctor Colombo         *pr_out = FIELD_EX64(env->msr, MSR, PR);
7535118ebe8SLucas Mateus Castro (alqotel)         return false;
7545118ebe8SLucas Mateus Castro (alqotel)     }
7555118ebe8SLucas Mateus Castro (alqotel) }
7565118ebe8SLucas Mateus Castro (alqotel) 
7575118ebe8SLucas Mateus Castro (alqotel) /* Check if the tlb found by hashing really matches */
7585118ebe8SLucas Mateus Castro (alqotel) static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
7595118ebe8SLucas Mateus Castro (alqotel)                                  hwaddr *raddr, int *prot,
7605118ebe8SLucas Mateus Castro (alqotel)                                  target_ulong address,
7615118ebe8SLucas Mateus Castro (alqotel)                                  MMUAccessType access_type, int mmu_idx)
7625118ebe8SLucas Mateus Castro (alqotel) {
7635118ebe8SLucas Mateus Castro (alqotel)     uint32_t epid;
7645118ebe8SLucas Mateus Castro (alqotel)     bool as, pr;
7655118ebe8SLucas Mateus Castro (alqotel)     bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
7665118ebe8SLucas Mateus Castro (alqotel) 
7675118ebe8SLucas Mateus Castro (alqotel)     if (!use_epid) {
7685118ebe8SLucas Mateus Castro (alqotel)         if (ppcmas_tlb_check(env, tlb, raddr, address,
7695118ebe8SLucas Mateus Castro (alqotel)                              env->spr[SPR_BOOKE_PID]) >= 0) {
7705118ebe8SLucas Mateus Castro (alqotel)             goto found_tlb;
7715118ebe8SLucas Mateus Castro (alqotel)         }
7725118ebe8SLucas Mateus Castro (alqotel) 
7735118ebe8SLucas Mateus Castro (alqotel)         if (env->spr[SPR_BOOKE_PID1] &&
7745118ebe8SLucas Mateus Castro (alqotel)             ppcmas_tlb_check(env, tlb, raddr, address,
7755118ebe8SLucas Mateus Castro (alqotel)                              env->spr[SPR_BOOKE_PID1]) >= 0) {
7765118ebe8SLucas Mateus Castro (alqotel)             goto found_tlb;
7775118ebe8SLucas Mateus Castro (alqotel)         }
7785118ebe8SLucas Mateus Castro (alqotel) 
7795118ebe8SLucas Mateus Castro (alqotel)         if (env->spr[SPR_BOOKE_PID2] &&
7805118ebe8SLucas Mateus Castro (alqotel)             ppcmas_tlb_check(env, tlb, raddr, address,
7815118ebe8SLucas Mateus Castro (alqotel)                              env->spr[SPR_BOOKE_PID2]) >= 0) {
7825118ebe8SLucas Mateus Castro (alqotel)             goto found_tlb;
7835118ebe8SLucas Mateus Castro (alqotel)         }
7845118ebe8SLucas Mateus Castro (alqotel)     } else {
7855118ebe8SLucas Mateus Castro (alqotel)         if (ppcmas_tlb_check(env, tlb, raddr, address, epid) >= 0) {
7865118ebe8SLucas Mateus Castro (alqotel)             goto found_tlb;
7875118ebe8SLucas Mateus Castro (alqotel)         }
7885118ebe8SLucas Mateus Castro (alqotel)     }
7895118ebe8SLucas Mateus Castro (alqotel) 
790e4cadfbeSBernhard Beschow     qemu_log_mask(CPU_LOG_MMU, "%s: No TLB entry found for effective address "
791e4cadfbeSBernhard Beschow                   "0x" TARGET_FMT_lx "\n", __func__, address);
7925118ebe8SLucas Mateus Castro (alqotel)     return -1;
7935118ebe8SLucas Mateus Castro (alqotel) 
7945118ebe8SLucas Mateus Castro (alqotel) found_tlb:
7955118ebe8SLucas Mateus Castro (alqotel) 
7963f520078SBALATON Zoltan     /* Check the address space and permissions */
7973f520078SBALATON Zoltan     if (access_type == MMU_INST_FETCH) {
7983f520078SBALATON Zoltan         /* There is no way to fetch code using epid load */
7993f520078SBALATON Zoltan         assert(!use_epid);
8003f520078SBALATON Zoltan         as = FIELD_EX64(env->msr, MSR, IR);
8013f520078SBALATON Zoltan     }
8023f520078SBALATON Zoltan 
8033f520078SBALATON Zoltan     if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
8043f520078SBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
8053f520078SBALATON Zoltan         return -1;
8063f520078SBALATON Zoltan     }
8073f520078SBALATON Zoltan 
808750fbe33SBALATON Zoltan     *prot = 0;
8095118ebe8SLucas Mateus Castro (alqotel)     if (pr) {
8105118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_UR) {
811750fbe33SBALATON Zoltan             *prot |= PAGE_READ;
8125118ebe8SLucas Mateus Castro (alqotel)         }
8135118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_UW) {
814750fbe33SBALATON Zoltan             *prot |= PAGE_WRITE;
8155118ebe8SLucas Mateus Castro (alqotel)         }
8165118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_UX) {
817750fbe33SBALATON Zoltan             *prot |= PAGE_EXEC;
8185118ebe8SLucas Mateus Castro (alqotel)         }
8195118ebe8SLucas Mateus Castro (alqotel)     } else {
8205118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_SR) {
821750fbe33SBALATON Zoltan             *prot |= PAGE_READ;
8225118ebe8SLucas Mateus Castro (alqotel)         }
8235118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_SW) {
824750fbe33SBALATON Zoltan             *prot |= PAGE_WRITE;
8255118ebe8SLucas Mateus Castro (alqotel)         }
8265118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_SX) {
827750fbe33SBALATON Zoltan             *prot |= PAGE_EXEC;
8285118ebe8SLucas Mateus Castro (alqotel)         }
8295118ebe8SLucas Mateus Castro (alqotel)     }
830750fbe33SBALATON Zoltan     if (*prot & prot_for_access_type(access_type)) {
83156964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
8325118ebe8SLucas Mateus Castro (alqotel)         return 0;
8335118ebe8SLucas Mateus Castro (alqotel)     }
8345118ebe8SLucas Mateus Castro (alqotel) 
835750fbe33SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot);
8365118ebe8SLucas Mateus Castro (alqotel)     return access_type == MMU_INST_FETCH ? -3 : -2;
8375118ebe8SLucas Mateus Castro (alqotel) }
8385118ebe8SLucas Mateus Castro (alqotel) 
839e8a9c0fbSBALATON Zoltan static int mmubooke206_get_physical_address(CPUPPCState *env, hwaddr *raddr,
840e8a9c0fbSBALATON Zoltan                                             int *prot, target_ulong address,
8415118ebe8SLucas Mateus Castro (alqotel)                                             MMUAccessType access_type,
8425118ebe8SLucas Mateus Castro (alqotel)                                             int mmu_idx)
8435118ebe8SLucas Mateus Castro (alqotel) {
8445118ebe8SLucas Mateus Castro (alqotel)     ppcmas_tlb_t *tlb;
845e8a9c0fbSBALATON Zoltan     int i, j, ret = -1;
8465118ebe8SLucas Mateus Castro (alqotel) 
8475118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
8485118ebe8SLucas Mateus Castro (alqotel)         int ways = booke206_tlb_ways(env, i);
8495118ebe8SLucas Mateus Castro (alqotel)         for (j = 0; j < ways; j++) {
8505118ebe8SLucas Mateus Castro (alqotel)             tlb = booke206_get_tlbm(env, i, address, j);
8515118ebe8SLucas Mateus Castro (alqotel)             if (!tlb) {
8525118ebe8SLucas Mateus Castro (alqotel)                 continue;
8535118ebe8SLucas Mateus Castro (alqotel)             }
854e8a9c0fbSBALATON Zoltan             ret = mmubooke206_check_tlb(env, tlb, raddr, prot, address,
8555118ebe8SLucas Mateus Castro (alqotel)                                         access_type, mmu_idx);
8565118ebe8SLucas Mateus Castro (alqotel)             if (ret != -1) {
8575118ebe8SLucas Mateus Castro (alqotel)                 goto found_tlb;
8585118ebe8SLucas Mateus Castro (alqotel)             }
8595118ebe8SLucas Mateus Castro (alqotel)         }
8605118ebe8SLucas Mateus Castro (alqotel)     }
8615118ebe8SLucas Mateus Castro (alqotel) 
8625118ebe8SLucas Mateus Castro (alqotel) found_tlb:
8635118ebe8SLucas Mateus Castro (alqotel) 
864e8a9c0fbSBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => "
865e8a9c0fbSBALATON Zoltan                   HWADDR_FMT_plx " %d %d\n", __func__,
866e8a9c0fbSBALATON Zoltan                   ret < 0 ? "refused" : "granted", address,
867e8a9c0fbSBALATON Zoltan                   ret < 0 ? -1 : *raddr, ret == -1 ? 0 : *prot, ret);
8685118ebe8SLucas Mateus Castro (alqotel)     return ret;
8695118ebe8SLucas Mateus Castro (alqotel) }
8705118ebe8SLucas Mateus Castro (alqotel) 
8715118ebe8SLucas Mateus Castro (alqotel) static const char *book3e_tsize_to_str[32] = {
8725118ebe8SLucas Mateus Castro (alqotel)     "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
8735118ebe8SLucas Mateus Castro (alqotel)     "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
8745118ebe8SLucas Mateus Castro (alqotel)     "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
8755118ebe8SLucas Mateus Castro (alqotel)     "1T", "2T"
8765118ebe8SLucas Mateus Castro (alqotel) };
8775118ebe8SLucas Mateus Castro (alqotel) 
8785118ebe8SLucas Mateus Castro (alqotel) static void mmubooke_dump_mmu(CPUPPCState *env)
8795118ebe8SLucas Mateus Castro (alqotel) {
8805118ebe8SLucas Mateus Castro (alqotel)     ppcemb_tlb_t *entry;
8815118ebe8SLucas Mateus Castro (alqotel)     int i;
8825118ebe8SLucas Mateus Castro (alqotel) 
88305739977SPhilippe Mathieu-Daudé #ifdef CONFIG_KVM
8845118ebe8SLucas Mateus Castro (alqotel)     if (kvm_enabled() && !env->kvm_sw_tlb) {
8855118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("Cannot access KVM TLB\n");
8865118ebe8SLucas Mateus Castro (alqotel)         return;
8875118ebe8SLucas Mateus Castro (alqotel)     }
88805739977SPhilippe Mathieu-Daudé #endif
8895118ebe8SLucas Mateus Castro (alqotel) 
8905118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nTLB:\n");
8915118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("Effective          Physical           Size PID   Prot     "
8925118ebe8SLucas Mateus Castro (alqotel)                 "Attr\n");
8935118ebe8SLucas Mateus Castro (alqotel) 
8945118ebe8SLucas Mateus Castro (alqotel)     entry = &env->tlb.tlbe[0];
8955118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_tlb; i++, entry++) {
8965118ebe8SLucas Mateus Castro (alqotel)         hwaddr ea, pa;
8975118ebe8SLucas Mateus Castro (alqotel)         target_ulong mask;
8985118ebe8SLucas Mateus Castro (alqotel)         uint64_t size = (uint64_t)entry->size;
8995118ebe8SLucas Mateus Castro (alqotel)         char size_buf[20];
9005118ebe8SLucas Mateus Castro (alqotel) 
9015118ebe8SLucas Mateus Castro (alqotel)         /* Check valid flag */
9025118ebe8SLucas Mateus Castro (alqotel)         if (!(entry->prot & PAGE_VALID)) {
9035118ebe8SLucas Mateus Castro (alqotel)             continue;
9045118ebe8SLucas Mateus Castro (alqotel)         }
9055118ebe8SLucas Mateus Castro (alqotel) 
9065118ebe8SLucas Mateus Castro (alqotel)         mask = ~(entry->size - 1);
9075118ebe8SLucas Mateus Castro (alqotel)         ea = entry->EPN & mask;
9085118ebe8SLucas Mateus Castro (alqotel)         pa = entry->RPN & mask;
9095118ebe8SLucas Mateus Castro (alqotel)         /* Extend the physical address to 36 bits */
9105118ebe8SLucas Mateus Castro (alqotel)         pa |= (hwaddr)(entry->RPN & 0xF) << 32;
9115118ebe8SLucas Mateus Castro (alqotel)         if (size >= 1 * MiB) {
9125118ebe8SLucas Mateus Castro (alqotel)             snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / MiB);
9135118ebe8SLucas Mateus Castro (alqotel)         } else {
9145118ebe8SLucas Mateus Castro (alqotel)             snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size / KiB);
9155118ebe8SLucas Mateus Castro (alqotel)         }
9165118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
9175118ebe8SLucas Mateus Castro (alqotel)                     (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
9185118ebe8SLucas Mateus Castro (alqotel)                     entry->prot, entry->attr);
9195118ebe8SLucas Mateus Castro (alqotel)     }
9205118ebe8SLucas Mateus Castro (alqotel) 
9215118ebe8SLucas Mateus Castro (alqotel) }
9225118ebe8SLucas Mateus Castro (alqotel) 
9235118ebe8SLucas Mateus Castro (alqotel) static void mmubooke206_dump_one_tlb(CPUPPCState *env, int tlbn, int offset,
9245118ebe8SLucas Mateus Castro (alqotel)                                      int tlbsize)
9255118ebe8SLucas Mateus Castro (alqotel) {
9265118ebe8SLucas Mateus Castro (alqotel)     ppcmas_tlb_t *entry;
9275118ebe8SLucas Mateus Castro (alqotel)     int i;
9285118ebe8SLucas Mateus Castro (alqotel) 
9295118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nTLB%d:\n", tlbn);
9305118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("Effective          Physical           Size TID   TS SRWX"
9315118ebe8SLucas Mateus Castro (alqotel)                 " URWX WIMGE U0123\n");
9325118ebe8SLucas Mateus Castro (alqotel) 
9335118ebe8SLucas Mateus Castro (alqotel)     entry = &env->tlb.tlbm[offset];
9345118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < tlbsize; i++, entry++) {
9355118ebe8SLucas Mateus Castro (alqotel)         hwaddr ea, pa, size;
9365118ebe8SLucas Mateus Castro (alqotel)         int tsize;
9375118ebe8SLucas Mateus Castro (alqotel) 
9385118ebe8SLucas Mateus Castro (alqotel)         if (!(entry->mas1 & MAS1_VALID)) {
9395118ebe8SLucas Mateus Castro (alqotel)             continue;
9405118ebe8SLucas Mateus Castro (alqotel)         }
9415118ebe8SLucas Mateus Castro (alqotel) 
9425118ebe8SLucas Mateus Castro (alqotel)         tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
9435118ebe8SLucas Mateus Castro (alqotel)         size = 1024ULL << tsize;
9445118ebe8SLucas Mateus Castro (alqotel)         ea = entry->mas2 & ~(size - 1);
9455118ebe8SLucas Mateus Castro (alqotel)         pa = entry->mas7_3 & ~(size - 1);
9465118ebe8SLucas Mateus Castro (alqotel) 
9475118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u  S%c%c%c"
9485118ebe8SLucas Mateus Castro (alqotel)                     " U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
9495118ebe8SLucas Mateus Castro (alqotel)                     (uint64_t)ea, (uint64_t)pa,
9505118ebe8SLucas Mateus Castro (alqotel)                     book3e_tsize_to_str[tsize],
9515118ebe8SLucas Mateus Castro (alqotel)                     (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
9525118ebe8SLucas Mateus Castro (alqotel)                     (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
9535118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_SR ? 'R' : '-',
9545118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_SW ? 'W' : '-',
9555118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_SX ? 'X' : '-',
9565118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_UR ? 'R' : '-',
9575118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_UW ? 'W' : '-',
9585118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_UX ? 'X' : '-',
9595118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_W ? 'W' : '-',
9605118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_I ? 'I' : '-',
9615118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_M ? 'M' : '-',
9625118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_G ? 'G' : '-',
9635118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_E ? 'E' : '-',
9645118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U0 ? '0' : '-',
9655118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U1 ? '1' : '-',
9665118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U2 ? '2' : '-',
9675118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U3 ? '3' : '-');
9685118ebe8SLucas Mateus Castro (alqotel)     }
9695118ebe8SLucas Mateus Castro (alqotel) }
9705118ebe8SLucas Mateus Castro (alqotel) 
9715118ebe8SLucas Mateus Castro (alqotel) static void mmubooke206_dump_mmu(CPUPPCState *env)
9725118ebe8SLucas Mateus Castro (alqotel) {
9735118ebe8SLucas Mateus Castro (alqotel)     int offset = 0;
9745118ebe8SLucas Mateus Castro (alqotel)     int i;
9755118ebe8SLucas Mateus Castro (alqotel) 
97605739977SPhilippe Mathieu-Daudé #ifdef CONFIG_KVM
9775118ebe8SLucas Mateus Castro (alqotel)     if (kvm_enabled() && !env->kvm_sw_tlb) {
9785118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("Cannot access KVM TLB\n");
9795118ebe8SLucas Mateus Castro (alqotel)         return;
9805118ebe8SLucas Mateus Castro (alqotel)     }
98105739977SPhilippe Mathieu-Daudé #endif
9825118ebe8SLucas Mateus Castro (alqotel) 
9835118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
9845118ebe8SLucas Mateus Castro (alqotel)         int size = booke206_tlb_size(env, i);
9855118ebe8SLucas Mateus Castro (alqotel) 
9865118ebe8SLucas Mateus Castro (alqotel)         if (size == 0) {
9875118ebe8SLucas Mateus Castro (alqotel)             continue;
9885118ebe8SLucas Mateus Castro (alqotel)         }
9895118ebe8SLucas Mateus Castro (alqotel) 
9905118ebe8SLucas Mateus Castro (alqotel)         mmubooke206_dump_one_tlb(env, i, offset, size);
9915118ebe8SLucas Mateus Castro (alqotel)         offset += size;
9925118ebe8SLucas Mateus Castro (alqotel)     }
9935118ebe8SLucas Mateus Castro (alqotel) }
9945118ebe8SLucas Mateus Castro (alqotel) 
9955118ebe8SLucas Mateus Castro (alqotel) static void mmu6xx_dump_BATs(CPUPPCState *env, int type)
9965118ebe8SLucas Mateus Castro (alqotel) {
9975118ebe8SLucas Mateus Castro (alqotel)     target_ulong *BATlt, *BATut, *BATu, *BATl;
9985118ebe8SLucas Mateus Castro (alqotel)     target_ulong BEPIl, BEPIu, bl;
9995118ebe8SLucas Mateus Castro (alqotel)     int i;
10005118ebe8SLucas Mateus Castro (alqotel) 
10015118ebe8SLucas Mateus Castro (alqotel)     switch (type) {
10025118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_CODE:
10035118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->IBAT[1];
10045118ebe8SLucas Mateus Castro (alqotel)         BATut = env->IBAT[0];
10055118ebe8SLucas Mateus Castro (alqotel)         break;
10065118ebe8SLucas Mateus Castro (alqotel)     default:
10075118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->DBAT[1];
10085118ebe8SLucas Mateus Castro (alqotel)         BATut = env->DBAT[0];
10095118ebe8SLucas Mateus Castro (alqotel)         break;
10105118ebe8SLucas Mateus Castro (alqotel)     }
10115118ebe8SLucas Mateus Castro (alqotel) 
10125118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_BATs; i++) {
10135118ebe8SLucas Mateus Castro (alqotel)         BATu = &BATut[i];
10145118ebe8SLucas Mateus Castro (alqotel)         BATl = &BATlt[i];
10155118ebe8SLucas Mateus Castro (alqotel)         BEPIu = *BATu & 0xF0000000;
10165118ebe8SLucas Mateus Castro (alqotel)         BEPIl = *BATu & 0x0FFE0000;
10175118ebe8SLucas Mateus Castro (alqotel)         bl = (*BATu & 0x00001FFC) << 15;
10185118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("%s BAT%d BATu " TARGET_FMT_lx
10195118ebe8SLucas Mateus Castro (alqotel)                     " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
10205118ebe8SLucas Mateus Castro (alqotel)                     TARGET_FMT_lx " " TARGET_FMT_lx "\n",
10215118ebe8SLucas Mateus Castro (alqotel)                     type == ACCESS_CODE ? "code" : "data", i,
10225118ebe8SLucas Mateus Castro (alqotel)                     *BATu, *BATl, BEPIu, BEPIl, bl);
10235118ebe8SLucas Mateus Castro (alqotel)     }
10245118ebe8SLucas Mateus Castro (alqotel) }
10255118ebe8SLucas Mateus Castro (alqotel) 
10265118ebe8SLucas Mateus Castro (alqotel) static void mmu6xx_dump_mmu(CPUPPCState *env)
10275118ebe8SLucas Mateus Castro (alqotel) {
10285118ebe8SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = env_archcpu(env);
10295118ebe8SLucas Mateus Castro (alqotel)     ppc6xx_tlb_t *tlb;
10305118ebe8SLucas Mateus Castro (alqotel)     target_ulong sr;
10315118ebe8SLucas Mateus Castro (alqotel)     int type, way, entry, i;
10325118ebe8SLucas Mateus Castro (alqotel) 
10335118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu));
10345118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu));
10355118ebe8SLucas Mateus Castro (alqotel) 
10365118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nSegment registers:\n");
10375118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < 32; i++) {
10385118ebe8SLucas Mateus Castro (alqotel)         sr = env->sr[i];
10395118ebe8SLucas Mateus Castro (alqotel)         if (sr & 0x80000000) {
10405118ebe8SLucas Mateus Castro (alqotel)             qemu_printf("%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
10415118ebe8SLucas Mateus Castro (alqotel)                         "CNTLR_SPEC=0x%05x\n", i,
10425118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
10435118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
10445118ebe8SLucas Mateus Castro (alqotel)                         (uint32_t)(sr & 0xFFFFF));
10455118ebe8SLucas Mateus Castro (alqotel)         } else {
10465118ebe8SLucas Mateus Castro (alqotel)             qemu_printf("%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
10475118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
10485118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
10495118ebe8SLucas Mateus Castro (alqotel)                         (uint32_t)(sr & 0x00FFFFFF));
10505118ebe8SLucas Mateus Castro (alqotel)         }
10515118ebe8SLucas Mateus Castro (alqotel)     }
10525118ebe8SLucas Mateus Castro (alqotel) 
10535118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nBATs:\n");
10545118ebe8SLucas Mateus Castro (alqotel)     mmu6xx_dump_BATs(env, ACCESS_INT);
10555118ebe8SLucas Mateus Castro (alqotel)     mmu6xx_dump_BATs(env, ACCESS_CODE);
10565118ebe8SLucas Mateus Castro (alqotel) 
10575118ebe8SLucas Mateus Castro (alqotel)     if (env->id_tlbs != 1) {
10585118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("ERROR: 6xx MMU should have separated TLB"
10595118ebe8SLucas Mateus Castro (alqotel)                     " for code and data\n");
10605118ebe8SLucas Mateus Castro (alqotel)     }
10615118ebe8SLucas Mateus Castro (alqotel) 
10625118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nTLBs                       [EPN    EPN + SIZE]\n");
10635118ebe8SLucas Mateus Castro (alqotel) 
10645118ebe8SLucas Mateus Castro (alqotel)     for (type = 0; type < 2; type++) {
10655118ebe8SLucas Mateus Castro (alqotel)         for (way = 0; way < env->nb_ways; way++) {
10665118ebe8SLucas Mateus Castro (alqotel)             for (entry = env->nb_tlb * type + env->tlb_per_way * way;
10675118ebe8SLucas Mateus Castro (alqotel)                  entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
10685118ebe8SLucas Mateus Castro (alqotel)                  entry++) {
10695118ebe8SLucas Mateus Castro (alqotel) 
10705118ebe8SLucas Mateus Castro (alqotel)                 tlb = &env->tlb.tlb6[entry];
10715118ebe8SLucas Mateus Castro (alqotel)                 qemu_printf("%s TLB %02d/%02d way:%d %s ["
10725118ebe8SLucas Mateus Castro (alqotel)                             TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
10735118ebe8SLucas Mateus Castro (alqotel)                             type ? "code" : "data", entry % env->nb_tlb,
10745118ebe8SLucas Mateus Castro (alqotel)                             env->nb_tlb, way,
10755118ebe8SLucas Mateus Castro (alqotel)                             pte_is_valid(tlb->pte0) ? "valid" : "inval",
10765118ebe8SLucas Mateus Castro (alqotel)                             tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
10775118ebe8SLucas Mateus Castro (alqotel)             }
10785118ebe8SLucas Mateus Castro (alqotel)         }
10795118ebe8SLucas Mateus Castro (alqotel)     }
10805118ebe8SLucas Mateus Castro (alqotel) }
10815118ebe8SLucas Mateus Castro (alqotel) 
10825118ebe8SLucas Mateus Castro (alqotel) void dump_mmu(CPUPPCState *env)
10835118ebe8SLucas Mateus Castro (alqotel) {
10845118ebe8SLucas Mateus Castro (alqotel)     switch (env->mmu_model) {
10855118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_BOOKE:
10865118ebe8SLucas Mateus Castro (alqotel)         mmubooke_dump_mmu(env);
10875118ebe8SLucas Mateus Castro (alqotel)         break;
10885118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_BOOKE206:
10895118ebe8SLucas Mateus Castro (alqotel)         mmubooke206_dump_mmu(env);
10905118ebe8SLucas Mateus Castro (alqotel)         break;
10915118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_SOFT_6xx:
10925118ebe8SLucas Mateus Castro (alqotel)         mmu6xx_dump_mmu(env);
10935118ebe8SLucas Mateus Castro (alqotel)         break;
10945118ebe8SLucas Mateus Castro (alqotel) #if defined(TARGET_PPC64)
10955118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_64B:
10965118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_03:
10975118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_06:
10985118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_07:
10995118ebe8SLucas Mateus Castro (alqotel)         dump_slb(env_archcpu(env));
11005118ebe8SLucas Mateus Castro (alqotel)         break;
11015118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_3_00:
11025118ebe8SLucas Mateus Castro (alqotel)         if (ppc64_v3_radix(env_archcpu(env))) {
11035118ebe8SLucas Mateus Castro (alqotel)             qemu_log_mask(LOG_UNIMP, "%s: the PPC64 MMU is unsupported\n",
11045118ebe8SLucas Mateus Castro (alqotel)                           __func__);
11055118ebe8SLucas Mateus Castro (alqotel)         } else {
11065118ebe8SLucas Mateus Castro (alqotel)             dump_slb(env_archcpu(env));
11075118ebe8SLucas Mateus Castro (alqotel)         }
11085118ebe8SLucas Mateus Castro (alqotel)         break;
11095118ebe8SLucas Mateus Castro (alqotel) #endif
11105118ebe8SLucas Mateus Castro (alqotel)     default:
11115118ebe8SLucas Mateus Castro (alqotel)         qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
11125118ebe8SLucas Mateus Castro (alqotel)     }
11135118ebe8SLucas Mateus Castro (alqotel) }
11145118ebe8SLucas Mateus Castro (alqotel) 
11155118ebe8SLucas Mateus Castro (alqotel) int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx,
11165118ebe8SLucas Mateus Castro (alqotel)                                      target_ulong eaddr,
11175118ebe8SLucas Mateus Castro (alqotel)                                      MMUAccessType access_type, int type,
11185118ebe8SLucas Mateus Castro (alqotel)                                      int mmu_idx)
11195118ebe8SLucas Mateus Castro (alqotel) {
11205118ebe8SLucas Mateus Castro (alqotel)     switch (env->mmu_model) {
11215118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_SOFT_6xx:
112254968516SBALATON Zoltan         return mmu6xx_get_physical_address(env, ctx, eaddr, access_type, type);
11235118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_SOFT_4xx:
11245cc867a6SBALATON Zoltan         return mmu40x_get_physical_address(env, &ctx->raddr, &ctx->prot, eaddr,
11255cc867a6SBALATON Zoltan                                            access_type);
11265118ebe8SLucas Mateus Castro (alqotel)     default:
11275118ebe8SLucas Mateus Castro (alqotel)         cpu_abort(env_cpu(env), "Unknown or invalid MMU model\n");
11285118ebe8SLucas Mateus Castro (alqotel)     }
11295118ebe8SLucas Mateus Castro (alqotel) }
11305118ebe8SLucas Mateus Castro (alqotel) 
11315118ebe8SLucas Mateus Castro (alqotel) static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
11325118ebe8SLucas Mateus Castro (alqotel)                                          MMUAccessType access_type, int mmu_idx)
11335118ebe8SLucas Mateus Castro (alqotel) {
11345118ebe8SLucas Mateus Castro (alqotel)     uint32_t epid;
11355118ebe8SLucas Mateus Castro (alqotel)     bool as, pr;
11365118ebe8SLucas Mateus Castro (alqotel)     uint32_t missed_tid = 0;
11375118ebe8SLucas Mateus Castro (alqotel)     bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
11385118ebe8SLucas Mateus Castro (alqotel) 
11395118ebe8SLucas Mateus Castro (alqotel)     if (access_type == MMU_INST_FETCH) {
11404d979c9fSVíctor Colombo         as = FIELD_EX64(env->msr, MSR, IR);
11415118ebe8SLucas Mateus Castro (alqotel)     }
11425118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
11435118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
11445118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
11455118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS3] = 0;
11465118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS6] = 0;
11475118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS7] = 0;
11485118ebe8SLucas Mateus Castro (alqotel) 
11495118ebe8SLucas Mateus Castro (alqotel)     /* AS */
11505118ebe8SLucas Mateus Castro (alqotel)     if (as) {
11515118ebe8SLucas Mateus Castro (alqotel)         env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
11525118ebe8SLucas Mateus Castro (alqotel)         env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
11535118ebe8SLucas Mateus Castro (alqotel)     }
11545118ebe8SLucas Mateus Castro (alqotel) 
11555118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
11565118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
11575118ebe8SLucas Mateus Castro (alqotel) 
11585118ebe8SLucas Mateus Castro (alqotel)     if (!use_epid) {
11595118ebe8SLucas Mateus Castro (alqotel)         switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
11605118ebe8SLucas Mateus Castro (alqotel)         case MAS4_TIDSELD_PID0:
11615118ebe8SLucas Mateus Castro (alqotel)             missed_tid = env->spr[SPR_BOOKE_PID];
11625118ebe8SLucas Mateus Castro (alqotel)             break;
11635118ebe8SLucas Mateus Castro (alqotel)         case MAS4_TIDSELD_PID1:
11645118ebe8SLucas Mateus Castro (alqotel)             missed_tid = env->spr[SPR_BOOKE_PID1];
11655118ebe8SLucas Mateus Castro (alqotel)             break;
11665118ebe8SLucas Mateus Castro (alqotel)         case MAS4_TIDSELD_PID2:
11675118ebe8SLucas Mateus Castro (alqotel)             missed_tid = env->spr[SPR_BOOKE_PID2];
11685118ebe8SLucas Mateus Castro (alqotel)             break;
11695118ebe8SLucas Mateus Castro (alqotel)         }
11705118ebe8SLucas Mateus Castro (alqotel)         env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
11715118ebe8SLucas Mateus Castro (alqotel)     } else {
11725118ebe8SLucas Mateus Castro (alqotel)         missed_tid = epid;
11735118ebe8SLucas Mateus Castro (alqotel)         env->spr[SPR_BOOKE_MAS6] |= missed_tid << 16;
11745118ebe8SLucas Mateus Castro (alqotel)     }
11755118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS1] |= (missed_tid << MAS1_TID_SHIFT);
11765118ebe8SLucas Mateus Castro (alqotel) 
11775118ebe8SLucas Mateus Castro (alqotel) 
11785118ebe8SLucas Mateus Castro (alqotel)     /* next victim logic */
11795118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
11805118ebe8SLucas Mateus Castro (alqotel)     env->last_way++;
11815118ebe8SLucas Mateus Castro (alqotel)     env->last_way &= booke206_tlb_ways(env, 0) - 1;
11825118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
11835118ebe8SLucas Mateus Castro (alqotel) }
11845118ebe8SLucas Mateus Castro (alqotel) 
1185ba91e5d0SBALATON Zoltan static bool ppc_booke_xlate(PowerPCCPU *cpu, vaddr eaddr,
1186ba91e5d0SBALATON Zoltan                             MMUAccessType access_type,
1187ba91e5d0SBALATON Zoltan                             hwaddr *raddrp, int *psizep, int *protp,
1188ba91e5d0SBALATON Zoltan                             int mmu_idx, bool guest_visible)
1189ba91e5d0SBALATON Zoltan {
1190ba91e5d0SBALATON Zoltan     CPUState *cs = CPU(cpu);
1191ba91e5d0SBALATON Zoltan     CPUPPCState *env = &cpu->env;
1192ba91e5d0SBALATON Zoltan     hwaddr raddr;
1193ba91e5d0SBALATON Zoltan     int prot, ret;
1194ba91e5d0SBALATON Zoltan 
1195ba91e5d0SBALATON Zoltan     if (env->mmu_model == POWERPC_MMU_BOOKE206) {
1196ba91e5d0SBALATON Zoltan         ret = mmubooke206_get_physical_address(env, &raddr, &prot, eaddr,
1197ba91e5d0SBALATON Zoltan                                                access_type, mmu_idx);
1198ba91e5d0SBALATON Zoltan     } else {
1199ba91e5d0SBALATON Zoltan         ret = mmubooke_get_physical_address(env, &raddr, &prot, eaddr,
1200ba91e5d0SBALATON Zoltan                                             access_type);
1201ba91e5d0SBALATON Zoltan     }
1202ba91e5d0SBALATON Zoltan     if (ret == 0) {
1203ba91e5d0SBALATON Zoltan         *raddrp = raddr;
1204ba91e5d0SBALATON Zoltan         *protp = prot;
1205ba91e5d0SBALATON Zoltan         *psizep = TARGET_PAGE_BITS;
1206ba91e5d0SBALATON Zoltan         return true;
1207ba91e5d0SBALATON Zoltan     } else if (!guest_visible) {
1208ba91e5d0SBALATON Zoltan         return false;
1209ba91e5d0SBALATON Zoltan     }
1210ba91e5d0SBALATON Zoltan 
1211ba91e5d0SBALATON Zoltan     log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
1212aa20e1c8SBALATON Zoltan     env->error_code = 0;
1213ba91e5d0SBALATON Zoltan     switch (ret) {
1214ba91e5d0SBALATON Zoltan     case -1:
1215ba91e5d0SBALATON Zoltan         /* No matches in page tables or TLB */
1216b18489b3SBALATON Zoltan         if (env->mmu_model == POWERPC_MMU_BOOKE206) {
1217b18489b3SBALATON Zoltan             booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
1218b18489b3SBALATON Zoltan         }
1219b18489b3SBALATON Zoltan         cs->exception_index = (access_type == MMU_INST_FETCH) ?
1220b18489b3SBALATON Zoltan                               POWERPC_EXCP_ITLB : POWERPC_EXCP_DTLB;
1221ba91e5d0SBALATON Zoltan         env->spr[SPR_BOOKE_DEAR] = eaddr;
1222ba91e5d0SBALATON Zoltan         env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
1223ba91e5d0SBALATON Zoltan         break;
1224ba91e5d0SBALATON Zoltan     case -2:
1225ba91e5d0SBALATON Zoltan         /* Access rights violation */
1226b18489b3SBALATON Zoltan         cs->exception_index = (access_type == MMU_INST_FETCH) ?
1227b18489b3SBALATON Zoltan                               POWERPC_EXCP_ISI : POWERPC_EXCP_DSI;
1228b18489b3SBALATON Zoltan         if (access_type != MMU_INST_FETCH) {
1229b18489b3SBALATON Zoltan             env->spr[SPR_BOOKE_DEAR] = eaddr;
1230b18489b3SBALATON Zoltan             env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
1231b18489b3SBALATON Zoltan         }
1232ba91e5d0SBALATON Zoltan         break;
1233ba91e5d0SBALATON Zoltan     case -3:
1234ba91e5d0SBALATON Zoltan         /* No execute protection violation */
1235ba91e5d0SBALATON Zoltan         cs->exception_index = POWERPC_EXCP_ISI;
1236ba91e5d0SBALATON Zoltan         env->spr[SPR_BOOKE_ESR] = 0;
1237ba91e5d0SBALATON Zoltan         break;
1238ba91e5d0SBALATON Zoltan     }
1239b18489b3SBALATON Zoltan 
1240ba91e5d0SBALATON Zoltan     return false;
1241ba91e5d0SBALATON Zoltan }
1242ba91e5d0SBALATON Zoltan 
1243c29f808aSBALATON Zoltan static bool ppc_real_mode_xlate(PowerPCCPU *cpu, vaddr eaddr,
1244c29f808aSBALATON Zoltan                                 MMUAccessType access_type,
1245c29f808aSBALATON Zoltan                                 hwaddr *raddrp, int *psizep, int *protp)
1246c29f808aSBALATON Zoltan {
1247c29f808aSBALATON Zoltan     CPUPPCState *env = &cpu->env;
1248c29f808aSBALATON Zoltan 
1249c29f808aSBALATON Zoltan     if (access_type == MMU_INST_FETCH ? !FIELD_EX64(env->msr, MSR, IR)
1250c29f808aSBALATON Zoltan                                       : !FIELD_EX64(env->msr, MSR, DR)) {
1251c29f808aSBALATON Zoltan         *raddrp = eaddr;
1252c29f808aSBALATON Zoltan         *protp = PAGE_RWX;
1253c29f808aSBALATON Zoltan         *psizep = TARGET_PAGE_BITS;
1254c29f808aSBALATON Zoltan         return true;
1255c29f808aSBALATON Zoltan     } else if (env->mmu_model == POWERPC_MMU_REAL) {
1256c29f808aSBALATON Zoltan         cpu_abort(CPU(cpu), "PowerPC in real mode shold not do translation\n");
1257c29f808aSBALATON Zoltan     }
1258c29f808aSBALATON Zoltan     return false;
1259c29f808aSBALATON Zoltan }
1260c29f808aSBALATON Zoltan 
1261*58b01325SBALATON Zoltan static bool ppc_40x_xlate(PowerPCCPU *cpu, vaddr eaddr,
1262*58b01325SBALATON Zoltan                           MMUAccessType access_type,
1263*58b01325SBALATON Zoltan                           hwaddr *raddrp, int *psizep, int *protp,
1264*58b01325SBALATON Zoltan                           int mmu_idx, bool guest_visible)
1265*58b01325SBALATON Zoltan {
1266*58b01325SBALATON Zoltan     CPUState *cs = CPU(cpu);
1267*58b01325SBALATON Zoltan     CPUPPCState *env = &cpu->env;
1268*58b01325SBALATON Zoltan     int ret;
1269*58b01325SBALATON Zoltan 
1270*58b01325SBALATON Zoltan     if (ppc_real_mode_xlate(cpu, eaddr, access_type, raddrp, psizep, protp)) {
1271*58b01325SBALATON Zoltan         return true;
1272*58b01325SBALATON Zoltan     }
1273*58b01325SBALATON Zoltan 
1274*58b01325SBALATON Zoltan     ret = mmu40x_get_physical_address(env, raddrp, protp, eaddr, access_type);
1275*58b01325SBALATON Zoltan     if (ret == 0) {
1276*58b01325SBALATON Zoltan         *psizep = TARGET_PAGE_BITS;
1277*58b01325SBALATON Zoltan         return true;
1278*58b01325SBALATON Zoltan     } else if (!guest_visible) {
1279*58b01325SBALATON Zoltan         return false;
1280*58b01325SBALATON Zoltan     }
1281*58b01325SBALATON Zoltan 
1282*58b01325SBALATON Zoltan     log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
1283*58b01325SBALATON Zoltan     if (access_type == MMU_INST_FETCH) {
1284*58b01325SBALATON Zoltan         switch (ret) {
1285*58b01325SBALATON Zoltan         case -1:
1286*58b01325SBALATON Zoltan             /* No matches in page tables or TLB */
1287*58b01325SBALATON Zoltan             cs->exception_index = POWERPC_EXCP_ITLB;
1288*58b01325SBALATON Zoltan             env->error_code = 0;
1289*58b01325SBALATON Zoltan             env->spr[SPR_40x_DEAR] = eaddr;
1290*58b01325SBALATON Zoltan             env->spr[SPR_40x_ESR] = 0x00000000;
1291*58b01325SBALATON Zoltan             break;
1292*58b01325SBALATON Zoltan         case -2:
1293*58b01325SBALATON Zoltan             /* Access rights violation */
1294*58b01325SBALATON Zoltan             cs->exception_index = POWERPC_EXCP_ISI;
1295*58b01325SBALATON Zoltan             env->error_code = 0x08000000;
1296*58b01325SBALATON Zoltan             break;
1297*58b01325SBALATON Zoltan         default:
1298*58b01325SBALATON Zoltan             g_assert_not_reached();
1299*58b01325SBALATON Zoltan         }
1300*58b01325SBALATON Zoltan     } else {
1301*58b01325SBALATON Zoltan         switch (ret) {
1302*58b01325SBALATON Zoltan         case -1:
1303*58b01325SBALATON Zoltan             /* No matches in page tables or TLB */
1304*58b01325SBALATON Zoltan             cs->exception_index = POWERPC_EXCP_DTLB;
1305*58b01325SBALATON Zoltan             env->error_code = 0;
1306*58b01325SBALATON Zoltan             env->spr[SPR_40x_DEAR] = eaddr;
1307*58b01325SBALATON Zoltan             if (access_type == MMU_DATA_STORE) {
1308*58b01325SBALATON Zoltan                 env->spr[SPR_40x_ESR] = 0x00800000;
1309*58b01325SBALATON Zoltan             } else {
1310*58b01325SBALATON Zoltan                 env->spr[SPR_40x_ESR] = 0x00000000;
1311*58b01325SBALATON Zoltan             }
1312*58b01325SBALATON Zoltan             break;
1313*58b01325SBALATON Zoltan         case -2:
1314*58b01325SBALATON Zoltan             /* Access rights violation */
1315*58b01325SBALATON Zoltan             cs->exception_index = POWERPC_EXCP_DSI;
1316*58b01325SBALATON Zoltan             env->error_code = 0;
1317*58b01325SBALATON Zoltan             env->spr[SPR_40x_DEAR] = eaddr;
1318*58b01325SBALATON Zoltan             if (access_type == MMU_DATA_STORE) {
1319*58b01325SBALATON Zoltan                 env->spr[SPR_40x_ESR] |= 0x00800000;
1320*58b01325SBALATON Zoltan             }
1321*58b01325SBALATON Zoltan             break;
1322*58b01325SBALATON Zoltan         default:
1323*58b01325SBALATON Zoltan             g_assert_not_reached();
1324*58b01325SBALATON Zoltan         }
1325*58b01325SBALATON Zoltan     }
1326*58b01325SBALATON Zoltan     return false;
1327*58b01325SBALATON Zoltan }
1328*58b01325SBALATON Zoltan 
13295118ebe8SLucas Mateus Castro (alqotel) /* Perform address translation */
13305118ebe8SLucas Mateus Castro (alqotel) /* TODO: Split this by mmu_model. */
13315118ebe8SLucas Mateus Castro (alqotel) static bool ppc_jumbo_xlate(PowerPCCPU *cpu, vaddr eaddr,
13325118ebe8SLucas Mateus Castro (alqotel)                             MMUAccessType access_type,
13335118ebe8SLucas Mateus Castro (alqotel)                             hwaddr *raddrp, int *psizep, int *protp,
13345118ebe8SLucas Mateus Castro (alqotel)                             int mmu_idx, bool guest_visible)
13355118ebe8SLucas Mateus Castro (alqotel) {
13365118ebe8SLucas Mateus Castro (alqotel)     CPUState *cs = CPU(cpu);
13375118ebe8SLucas Mateus Castro (alqotel)     CPUPPCState *env = &cpu->env;
13385118ebe8SLucas Mateus Castro (alqotel)     mmu_ctx_t ctx;
13395118ebe8SLucas Mateus Castro (alqotel)     int type;
13405118ebe8SLucas Mateus Castro (alqotel)     int ret;
13415118ebe8SLucas Mateus Castro (alqotel) 
1342c29f808aSBALATON Zoltan     if (ppc_real_mode_xlate(cpu, eaddr, access_type, raddrp, psizep, protp)) {
1343c29f808aSBALATON Zoltan         return true;
1344c29f808aSBALATON Zoltan     }
1345c29f808aSBALATON Zoltan 
13465118ebe8SLucas Mateus Castro (alqotel)     if (access_type == MMU_INST_FETCH) {
13475118ebe8SLucas Mateus Castro (alqotel)         /* code access */
13485118ebe8SLucas Mateus Castro (alqotel)         type = ACCESS_CODE;
13495118ebe8SLucas Mateus Castro (alqotel)     } else if (guest_visible) {
13505118ebe8SLucas Mateus Castro (alqotel)         /* data access */
13515118ebe8SLucas Mateus Castro (alqotel)         type = env->access_type;
13525118ebe8SLucas Mateus Castro (alqotel)     } else {
13535118ebe8SLucas Mateus Castro (alqotel)         type = ACCESS_INT;
13545118ebe8SLucas Mateus Castro (alqotel)     }
13555118ebe8SLucas Mateus Castro (alqotel) 
13565118ebe8SLucas Mateus Castro (alqotel)     ret = get_physical_address_wtlb(env, &ctx, eaddr, access_type,
13575118ebe8SLucas Mateus Castro (alqotel)                                     type, mmu_idx);
13585118ebe8SLucas Mateus Castro (alqotel)     if (ret == 0) {
13595118ebe8SLucas Mateus Castro (alqotel)         *raddrp = ctx.raddr;
13605118ebe8SLucas Mateus Castro (alqotel)         *protp = ctx.prot;
13615118ebe8SLucas Mateus Castro (alqotel)         *psizep = TARGET_PAGE_BITS;
13625118ebe8SLucas Mateus Castro (alqotel)         return true;
13639e9ca54cSBALATON Zoltan     } else if (!guest_visible) {
13649e9ca54cSBALATON Zoltan         return false;
13655118ebe8SLucas Mateus Castro (alqotel)     }
13665118ebe8SLucas Mateus Castro (alqotel) 
136756964585SCédric Le Goater     log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
13685118ebe8SLucas Mateus Castro (alqotel)     if (type == ACCESS_CODE) {
13695118ebe8SLucas Mateus Castro (alqotel)         switch (ret) {
13705118ebe8SLucas Mateus Castro (alqotel)         case -1:
13715118ebe8SLucas Mateus Castro (alqotel)             /* No matches in page tables or TLB */
13725118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_IFTLB;
13735118ebe8SLucas Mateus Castro (alqotel)             env->error_code = 1 << 18;
13745118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_IMISS] = eaddr;
13755118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
13765118ebe8SLucas Mateus Castro (alqotel)             goto tlb_miss;
13775118ebe8SLucas Mateus Castro (alqotel)         case -2:
13785118ebe8SLucas Mateus Castro (alqotel)             /* Access rights violation */
13795118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_ISI;
13805118ebe8SLucas Mateus Castro (alqotel)             env->error_code = 0x08000000;
13815118ebe8SLucas Mateus Castro (alqotel)             break;
13825118ebe8SLucas Mateus Castro (alqotel)         case -3:
13835118ebe8SLucas Mateus Castro (alqotel)             /* No execute protection violation */
13845118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_ISI;
1385ba91e5d0SBALATON Zoltan             env->error_code = 0x10000000;
13865118ebe8SLucas Mateus Castro (alqotel)             break;
13875118ebe8SLucas Mateus Castro (alqotel)         case -4:
13885118ebe8SLucas Mateus Castro (alqotel)             /* Direct store exception */
13895118ebe8SLucas Mateus Castro (alqotel)             /* No code fetch is allowed in direct-store areas */
13905118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_ISI;
13915118ebe8SLucas Mateus Castro (alqotel)             env->error_code = 0x10000000;
13925118ebe8SLucas Mateus Castro (alqotel)             break;
13935118ebe8SLucas Mateus Castro (alqotel)         }
13945118ebe8SLucas Mateus Castro (alqotel)     } else {
13955118ebe8SLucas Mateus Castro (alqotel)         switch (ret) {
13965118ebe8SLucas Mateus Castro (alqotel)         case -1:
13975118ebe8SLucas Mateus Castro (alqotel)             /* No matches in page tables or TLB */
13985118ebe8SLucas Mateus Castro (alqotel)             if (access_type == MMU_DATA_STORE) {
13995118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DSTLB;
14005118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 1 << 16;
14015118ebe8SLucas Mateus Castro (alqotel)             } else {
14025118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DLTLB;
14035118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 0;
14045118ebe8SLucas Mateus Castro (alqotel)             }
14055118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_DMISS] = eaddr;
14065118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
14075118ebe8SLucas Mateus Castro (alqotel) tlb_miss:
14085118ebe8SLucas Mateus Castro (alqotel)             env->error_code |= ctx.key << 19;
14095118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
14105118ebe8SLucas Mateus Castro (alqotel)                                   get_pteg_offset32(cpu, ctx.hash[0]);
14115118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
14125118ebe8SLucas Mateus Castro (alqotel)                                   get_pteg_offset32(cpu, ctx.hash[1]);
14135118ebe8SLucas Mateus Castro (alqotel)             break;
14145118ebe8SLucas Mateus Castro (alqotel)         case -2:
14155118ebe8SLucas Mateus Castro (alqotel)             /* Access rights violation */
14165118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_DSI;
14175118ebe8SLucas Mateus Castro (alqotel)             env->error_code = 0;
14185118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_DAR] = eaddr;
14195118ebe8SLucas Mateus Castro (alqotel)             if (access_type == MMU_DATA_STORE) {
14205118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DSISR] = 0x0A000000;
14215118ebe8SLucas Mateus Castro (alqotel)             } else {
14225118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DSISR] = 0x08000000;
14235118ebe8SLucas Mateus Castro (alqotel)             }
14245118ebe8SLucas Mateus Castro (alqotel)             break;
14255118ebe8SLucas Mateus Castro (alqotel)         case -4:
14265118ebe8SLucas Mateus Castro (alqotel)             /* Direct store exception */
14275118ebe8SLucas Mateus Castro (alqotel)             switch (type) {
14285118ebe8SLucas Mateus Castro (alqotel)             case ACCESS_FLOAT:
14295118ebe8SLucas Mateus Castro (alqotel)                 /* Floating point load/store */
14305118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_ALIGN;
14315118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = POWERPC_EXCP_ALIGN_FP;
14325118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DAR] = eaddr;
14335118ebe8SLucas Mateus Castro (alqotel)                 break;
14345118ebe8SLucas Mateus Castro (alqotel)             case ACCESS_RES:
14355118ebe8SLucas Mateus Castro (alqotel)                 /* lwarx, ldarx or stwcx. */
14365118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DSI;
14375118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 0;
14385118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DAR] = eaddr;
14395118ebe8SLucas Mateus Castro (alqotel)                 if (access_type == MMU_DATA_STORE) {
14405118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DSISR] = 0x06000000;
14415118ebe8SLucas Mateus Castro (alqotel)                 } else {
14425118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DSISR] = 0x04000000;
14435118ebe8SLucas Mateus Castro (alqotel)                 }
14445118ebe8SLucas Mateus Castro (alqotel)                 break;
14455118ebe8SLucas Mateus Castro (alqotel)             case ACCESS_EXT:
14465118ebe8SLucas Mateus Castro (alqotel)                 /* eciwx or ecowx */
14475118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DSI;
14485118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 0;
14495118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DAR] = eaddr;
14505118ebe8SLucas Mateus Castro (alqotel)                 if (access_type == MMU_DATA_STORE) {
14515118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DSISR] = 0x06100000;
14525118ebe8SLucas Mateus Castro (alqotel)                 } else {
14535118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DSISR] = 0x04100000;
14545118ebe8SLucas Mateus Castro (alqotel)                 }
14555118ebe8SLucas Mateus Castro (alqotel)                 break;
14565118ebe8SLucas Mateus Castro (alqotel)             default:
14575118ebe8SLucas Mateus Castro (alqotel)                 printf("DSI: invalid exception (%d)\n", ret);
14585118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_PROGRAM;
14599e9ca54cSBALATON Zoltan                 env->error_code = POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
14605118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DAR] = eaddr;
14615118ebe8SLucas Mateus Castro (alqotel)                 break;
14625118ebe8SLucas Mateus Castro (alqotel)             }
14635118ebe8SLucas Mateus Castro (alqotel)             break;
14645118ebe8SLucas Mateus Castro (alqotel)         }
14655118ebe8SLucas Mateus Castro (alqotel)     }
14665118ebe8SLucas Mateus Castro (alqotel)     return false;
14675118ebe8SLucas Mateus Castro (alqotel) }
14685118ebe8SLucas Mateus Castro (alqotel) 
14695118ebe8SLucas Mateus Castro (alqotel) /*****************************************************************************/
14705118ebe8SLucas Mateus Castro (alqotel) 
14715118ebe8SLucas Mateus Castro (alqotel) bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
14725118ebe8SLucas Mateus Castro (alqotel)                       hwaddr *raddrp, int *psizep, int *protp,
14735118ebe8SLucas Mateus Castro (alqotel)                       int mmu_idx, bool guest_visible)
14745118ebe8SLucas Mateus Castro (alqotel) {
14755118ebe8SLucas Mateus Castro (alqotel)     switch (cpu->env.mmu_model) {
14765118ebe8SLucas Mateus Castro (alqotel) #if defined(TARGET_PPC64)
14775118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_3_00:
14785118ebe8SLucas Mateus Castro (alqotel)         if (ppc64_v3_radix(cpu)) {
14795118ebe8SLucas Mateus Castro (alqotel)             return ppc_radix64_xlate(cpu, eaddr, access_type, raddrp,
14805118ebe8SLucas Mateus Castro (alqotel)                                      psizep, protp, mmu_idx, guest_visible);
14815118ebe8SLucas Mateus Castro (alqotel)         }
14825118ebe8SLucas Mateus Castro (alqotel)         /* fall through */
14835118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_64B:
14845118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_03:
14855118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_06:
14865118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_07:
14875118ebe8SLucas Mateus Castro (alqotel)         return ppc_hash64_xlate(cpu, eaddr, access_type,
14885118ebe8SLucas Mateus Castro (alqotel)                                 raddrp, psizep, protp, mmu_idx, guest_visible);
14895118ebe8SLucas Mateus Castro (alqotel) #endif
14905118ebe8SLucas Mateus Castro (alqotel) 
14915118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_32B:
14925118ebe8SLucas Mateus Castro (alqotel)         return ppc_hash32_xlate(cpu, eaddr, access_type, raddrp,
14935118ebe8SLucas Mateus Castro (alqotel)                                psizep, protp, mmu_idx, guest_visible);
1494ba91e5d0SBALATON Zoltan     case POWERPC_MMU_BOOKE:
1495ba91e5d0SBALATON Zoltan     case POWERPC_MMU_BOOKE206:
1496ba91e5d0SBALATON Zoltan         return ppc_booke_xlate(cpu, eaddr, access_type, raddrp,
1497ba91e5d0SBALATON Zoltan                                psizep, protp, mmu_idx, guest_visible);
1498*58b01325SBALATON Zoltan     case POWERPC_MMU_SOFT_4xx:
1499*58b01325SBALATON Zoltan         return ppc_40x_xlate(cpu, eaddr, access_type, raddrp,
1500*58b01325SBALATON Zoltan                              psizep, protp, mmu_idx, guest_visible);
1501c29f808aSBALATON Zoltan     case POWERPC_MMU_REAL:
1502c29f808aSBALATON Zoltan         return ppc_real_mode_xlate(cpu, eaddr, access_type, raddrp, psizep,
1503c29f808aSBALATON Zoltan                                    protp);
1504cfd5c128SBALATON Zoltan     case POWERPC_MMU_MPC8xx:
1505cfd5c128SBALATON Zoltan         cpu_abort(env_cpu(&cpu->env), "MPC8xx MMU model is not implemented\n");
15065118ebe8SLucas Mateus Castro (alqotel)     default:
15075118ebe8SLucas Mateus Castro (alqotel)         return ppc_jumbo_xlate(cpu, eaddr, access_type, raddrp,
15085118ebe8SLucas Mateus Castro (alqotel)                                psizep, protp, mmu_idx, guest_visible);
15095118ebe8SLucas Mateus Castro (alqotel)     }
15105118ebe8SLucas Mateus Castro (alqotel) }
15115118ebe8SLucas Mateus Castro (alqotel) 
15125118ebe8SLucas Mateus Castro (alqotel) hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
15135118ebe8SLucas Mateus Castro (alqotel) {
15145118ebe8SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = POWERPC_CPU(cs);
15155118ebe8SLucas Mateus Castro (alqotel)     hwaddr raddr;
15165118ebe8SLucas Mateus Castro (alqotel)     int s, p;
15175118ebe8SLucas Mateus Castro (alqotel) 
15185118ebe8SLucas Mateus Castro (alqotel)     /*
15195118ebe8SLucas Mateus Castro (alqotel)      * Some MMUs have separate TLBs for code and data. If we only
15205118ebe8SLucas Mateus Castro (alqotel)      * try an MMU_DATA_LOAD, we may not be able to read instructions
15215118ebe8SLucas Mateus Castro (alqotel)      * mapped by code TLBs, so we also try a MMU_INST_FETCH.
15225118ebe8SLucas Mateus Castro (alqotel)      */
15235118ebe8SLucas Mateus Castro (alqotel)     if (ppc_xlate(cpu, addr, MMU_DATA_LOAD, &raddr, &s, &p,
1524fb00f730SRichard Henderson                   ppc_env_mmu_index(&cpu->env, false), false) ||
15255118ebe8SLucas Mateus Castro (alqotel)         ppc_xlate(cpu, addr, MMU_INST_FETCH, &raddr, &s, &p,
1526fb00f730SRichard Henderson                   ppc_env_mmu_index(&cpu->env, true), false)) {
15275118ebe8SLucas Mateus Castro (alqotel)         return raddr & TARGET_PAGE_MASK;
15285118ebe8SLucas Mateus Castro (alqotel)     }
15295118ebe8SLucas Mateus Castro (alqotel)     return -1;
15305118ebe8SLucas Mateus Castro (alqotel) }
1531