xref: /qemu/target/ppc/mmu_common.c (revision e7baac649bb3d9d72a3e79fc43e360d7ac99aead)
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"
36*e7baac64SBALATON Zoltan #include "mmu-booke.h"
375118ebe8SLucas Mateus Castro (alqotel) 
385118ebe8SLucas Mateus Castro (alqotel) /* #define DUMP_PAGE_TABLES */
395118ebe8SLucas Mateus Castro (alqotel) 
40306b5320SBALATON Zoltan /* Context used internally during MMU translations */
41306b5320SBALATON Zoltan typedef struct {
42306b5320SBALATON Zoltan     hwaddr raddr;      /* Real address             */
43306b5320SBALATON Zoltan     hwaddr eaddr;      /* Effective address        */
44306b5320SBALATON Zoltan     int prot;          /* Protection bits          */
45306b5320SBALATON Zoltan     hwaddr hash[2];    /* Pagetable hash values    */
46306b5320SBALATON Zoltan     target_ulong ptem; /* Virtual segment ID | API */
47306b5320SBALATON Zoltan     int key;           /* Access key               */
48306b5320SBALATON Zoltan     int nx;            /* Non-execute area         */
49306b5320SBALATON Zoltan } mmu_ctx_t;
50306b5320SBALATON Zoltan 
51d6ae8ec6SLucas Mateus Castro (alqotel) void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
52d6ae8ec6SLucas Mateus Castro (alqotel) {
53d6ae8ec6SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = env_archcpu(env);
54d6ae8ec6SLucas Mateus Castro (alqotel)     qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
55d6ae8ec6SLucas Mateus Castro (alqotel)     assert(!cpu->env.has_hv_mode || !cpu->vhyp);
56d6ae8ec6SLucas Mateus Castro (alqotel) #if defined(TARGET_PPC64)
57d6ae8ec6SLucas Mateus Castro (alqotel)     if (mmu_is_64bit(env->mmu_model)) {
58d6ae8ec6SLucas Mateus Castro (alqotel)         target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE;
59d6ae8ec6SLucas Mateus Castro (alqotel)         target_ulong htabsize = value & SDR_64_HTABSIZE;
60d6ae8ec6SLucas Mateus Castro (alqotel) 
61d6ae8ec6SLucas Mateus Castro (alqotel)         if (value & ~sdr_mask) {
62d6ae8ec6SLucas Mateus Castro (alqotel)             qemu_log_mask(LOG_GUEST_ERROR, "Invalid bits 0x"TARGET_FMT_lx
63d6ae8ec6SLucas Mateus Castro (alqotel)                      " set in SDR1", value & ~sdr_mask);
64d6ae8ec6SLucas Mateus Castro (alqotel)             value &= sdr_mask;
65d6ae8ec6SLucas Mateus Castro (alqotel)         }
66d6ae8ec6SLucas Mateus Castro (alqotel)         if (htabsize > 28) {
67d6ae8ec6SLucas Mateus Castro (alqotel)             qemu_log_mask(LOG_GUEST_ERROR, "Invalid HTABSIZE 0x" TARGET_FMT_lx
68d6ae8ec6SLucas Mateus Castro (alqotel)                      " stored in SDR1", htabsize);
69d6ae8ec6SLucas Mateus Castro (alqotel)             return;
70d6ae8ec6SLucas Mateus Castro (alqotel)         }
71d6ae8ec6SLucas Mateus Castro (alqotel)     }
72d6ae8ec6SLucas Mateus Castro (alqotel) #endif /* defined(TARGET_PPC64) */
73d6ae8ec6SLucas Mateus Castro (alqotel)     /* FIXME: Should check for valid HTABMASK values in 32-bit case */
74d6ae8ec6SLucas Mateus Castro (alqotel)     env->spr[SPR_SDR1] = value;
75d6ae8ec6SLucas Mateus Castro (alqotel) }
76d6ae8ec6SLucas Mateus Castro (alqotel) 
775118ebe8SLucas Mateus Castro (alqotel) /*****************************************************************************/
785118ebe8SLucas Mateus Castro (alqotel) /* PowerPC MMU emulation */
795118ebe8SLucas Mateus Castro (alqotel) 
805118ebe8SLucas Mateus Castro (alqotel) static int pp_check(int key, int pp, int nx)
815118ebe8SLucas Mateus Castro (alqotel) {
825118ebe8SLucas Mateus Castro (alqotel)     int access;
835118ebe8SLucas Mateus Castro (alqotel) 
845118ebe8SLucas Mateus Castro (alqotel)     /* Compute access rights */
855118ebe8SLucas Mateus Castro (alqotel)     access = 0;
865118ebe8SLucas Mateus Castro (alqotel)     if (key == 0) {
875118ebe8SLucas Mateus Castro (alqotel)         switch (pp) {
885118ebe8SLucas Mateus Castro (alqotel)         case 0x0:
895118ebe8SLucas Mateus Castro (alqotel)         case 0x1:
905118ebe8SLucas Mateus Castro (alqotel)         case 0x2:
915118ebe8SLucas Mateus Castro (alqotel)             access |= PAGE_WRITE;
925118ebe8SLucas Mateus Castro (alqotel)             /* fall through */
935118ebe8SLucas Mateus Castro (alqotel)         case 0x3:
945118ebe8SLucas Mateus Castro (alqotel)             access |= PAGE_READ;
955118ebe8SLucas Mateus Castro (alqotel)             break;
965118ebe8SLucas Mateus Castro (alqotel)         }
975118ebe8SLucas Mateus Castro (alqotel)     } else {
985118ebe8SLucas Mateus Castro (alqotel)         switch (pp) {
995118ebe8SLucas Mateus Castro (alqotel)         case 0x0:
1005118ebe8SLucas Mateus Castro (alqotel)             access = 0;
1015118ebe8SLucas Mateus Castro (alqotel)             break;
1025118ebe8SLucas Mateus Castro (alqotel)         case 0x1:
1035118ebe8SLucas Mateus Castro (alqotel)         case 0x3:
1045118ebe8SLucas Mateus Castro (alqotel)             access = PAGE_READ;
1055118ebe8SLucas Mateus Castro (alqotel)             break;
1065118ebe8SLucas Mateus Castro (alqotel)         case 0x2:
1075118ebe8SLucas Mateus Castro (alqotel)             access = PAGE_READ | PAGE_WRITE;
1085118ebe8SLucas Mateus Castro (alqotel)             break;
1095118ebe8SLucas Mateus Castro (alqotel)         }
1105118ebe8SLucas Mateus Castro (alqotel)     }
1115118ebe8SLucas Mateus Castro (alqotel)     if (nx == 0) {
1125118ebe8SLucas Mateus Castro (alqotel)         access |= PAGE_EXEC;
1135118ebe8SLucas Mateus Castro (alqotel)     }
1145118ebe8SLucas Mateus Castro (alqotel) 
1155118ebe8SLucas Mateus Castro (alqotel)     return access;
1165118ebe8SLucas Mateus Castro (alqotel) }
1175118ebe8SLucas Mateus Castro (alqotel) 
1185118ebe8SLucas Mateus Castro (alqotel) int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
1195118ebe8SLucas Mateus Castro (alqotel)                                     int way, int is_code)
1205118ebe8SLucas Mateus Castro (alqotel) {
1215118ebe8SLucas Mateus Castro (alqotel)     int nr;
1225118ebe8SLucas Mateus Castro (alqotel) 
1235118ebe8SLucas Mateus Castro (alqotel)     /* Select TLB num in a way from address */
1245118ebe8SLucas Mateus Castro (alqotel)     nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
1255118ebe8SLucas Mateus Castro (alqotel)     /* Select TLB way */
1265118ebe8SLucas Mateus Castro (alqotel)     nr += env->tlb_per_way * way;
1275fd257f5SBALATON Zoltan     /* 6xx has separate TLBs for instructions and data */
1285fd257f5SBALATON Zoltan     if (is_code) {
1295118ebe8SLucas Mateus Castro (alqotel)         nr += env->nb_tlb;
1305118ebe8SLucas Mateus Castro (alqotel)     }
1315118ebe8SLucas Mateus Castro (alqotel) 
1325118ebe8SLucas Mateus Castro (alqotel)     return nr;
1335118ebe8SLucas Mateus Castro (alqotel) }
1345118ebe8SLucas Mateus Castro (alqotel) 
1355118ebe8SLucas Mateus Castro (alqotel) static int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
1365118ebe8SLucas Mateus Castro (alqotel)                                 target_ulong pte1, int h,
1375118ebe8SLucas Mateus Castro (alqotel)                                 MMUAccessType access_type)
1385118ebe8SLucas Mateus Castro (alqotel) {
1395118ebe8SLucas Mateus Castro (alqotel)     target_ulong ptem, mmask;
1405118ebe8SLucas Mateus Castro (alqotel)     int access, ret, pteh, ptev, pp;
1415118ebe8SLucas Mateus Castro (alqotel) 
1425118ebe8SLucas Mateus Castro (alqotel)     ret = -1;
1435118ebe8SLucas Mateus Castro (alqotel)     /* Check validity and table match */
1445118ebe8SLucas Mateus Castro (alqotel)     ptev = pte_is_valid(pte0);
1455118ebe8SLucas Mateus Castro (alqotel)     pteh = (pte0 >> 6) & 1;
1465118ebe8SLucas Mateus Castro (alqotel)     if (ptev && h == pteh) {
1475118ebe8SLucas Mateus Castro (alqotel)         /* Check vsid & api */
1485118ebe8SLucas Mateus Castro (alqotel)         ptem = pte0 & PTE_PTEM_MASK;
1495118ebe8SLucas Mateus Castro (alqotel)         mmask = PTE_CHECK_MASK;
1505118ebe8SLucas Mateus Castro (alqotel)         pp = pte1 & 0x00000003;
1515118ebe8SLucas Mateus Castro (alqotel)         if (ptem == ctx->ptem) {
1525118ebe8SLucas Mateus Castro (alqotel)             if (ctx->raddr != (hwaddr)-1ULL) {
1535118ebe8SLucas Mateus Castro (alqotel)                 /* all matches should have equal RPN, WIMG & PP */
1545118ebe8SLucas Mateus Castro (alqotel)                 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
1555118ebe8SLucas Mateus Castro (alqotel)                     qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
1565118ebe8SLucas Mateus Castro (alqotel)                     return -3;
1575118ebe8SLucas Mateus Castro (alqotel)                 }
1585118ebe8SLucas Mateus Castro (alqotel)             }
1595118ebe8SLucas Mateus Castro (alqotel)             /* Compute access rights */
1605118ebe8SLucas Mateus Castro (alqotel)             access = pp_check(ctx->key, pp, ctx->nx);
1615118ebe8SLucas Mateus Castro (alqotel)             /* Keep the matching PTE information */
1625118ebe8SLucas Mateus Castro (alqotel)             ctx->raddr = pte1;
1635118ebe8SLucas Mateus Castro (alqotel)             ctx->prot = access;
164cd1038ecSBALATON Zoltan             if (check_prot_access_type(ctx->prot, access_type)) {
1655118ebe8SLucas Mateus Castro (alqotel)                 /* Access granted */
1665118ebe8SLucas Mateus Castro (alqotel)                 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
167cd1038ecSBALATON Zoltan                 ret = 0;
1685118ebe8SLucas Mateus Castro (alqotel)             } else {
1695118ebe8SLucas Mateus Castro (alqotel)                 /* Access right violation */
1705118ebe8SLucas Mateus Castro (alqotel)                 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
171cd1038ecSBALATON Zoltan                 ret = -2;
1725118ebe8SLucas Mateus Castro (alqotel)             }
1735118ebe8SLucas Mateus Castro (alqotel)         }
1745118ebe8SLucas Mateus Castro (alqotel)     }
1755118ebe8SLucas Mateus Castro (alqotel) 
1765118ebe8SLucas Mateus Castro (alqotel)     return ret;
1775118ebe8SLucas Mateus Castro (alqotel) }
1785118ebe8SLucas Mateus Castro (alqotel) 
1795118ebe8SLucas Mateus Castro (alqotel) static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
1805118ebe8SLucas Mateus Castro (alqotel)                             int ret, MMUAccessType access_type)
1815118ebe8SLucas Mateus Castro (alqotel) {
1825118ebe8SLucas Mateus Castro (alqotel)     int store = 0;
1835118ebe8SLucas Mateus Castro (alqotel) 
1845118ebe8SLucas Mateus Castro (alqotel)     /* Update page flags */
1855118ebe8SLucas Mateus Castro (alqotel)     if (!(*pte1p & 0x00000100)) {
1865118ebe8SLucas Mateus Castro (alqotel)         /* Update accessed flag */
1875118ebe8SLucas Mateus Castro (alqotel)         *pte1p |= 0x00000100;
1885118ebe8SLucas Mateus Castro (alqotel)         store = 1;
1895118ebe8SLucas Mateus Castro (alqotel)     }
1905118ebe8SLucas Mateus Castro (alqotel)     if (!(*pte1p & 0x00000080)) {
1915118ebe8SLucas Mateus Castro (alqotel)         if (access_type == MMU_DATA_STORE && ret == 0) {
1925118ebe8SLucas Mateus Castro (alqotel)             /* Update changed flag */
1935118ebe8SLucas Mateus Castro (alqotel)             *pte1p |= 0x00000080;
1945118ebe8SLucas Mateus Castro (alqotel)             store = 1;
1955118ebe8SLucas Mateus Castro (alqotel)         } else {
1965118ebe8SLucas Mateus Castro (alqotel)             /* Force page fault for first write access */
1975118ebe8SLucas Mateus Castro (alqotel)             ctx->prot &= ~PAGE_WRITE;
1985118ebe8SLucas Mateus Castro (alqotel)         }
1995118ebe8SLucas Mateus Castro (alqotel)     }
2005118ebe8SLucas Mateus Castro (alqotel) 
2015118ebe8SLucas Mateus Castro (alqotel)     return store;
2025118ebe8SLucas Mateus Castro (alqotel) }
2035118ebe8SLucas Mateus Castro (alqotel) 
2045118ebe8SLucas Mateus Castro (alqotel) /* Software driven TLB helpers */
2055118ebe8SLucas Mateus Castro (alqotel) 
2065118ebe8SLucas Mateus Castro (alqotel) static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
2075118ebe8SLucas Mateus Castro (alqotel)                             target_ulong eaddr, MMUAccessType access_type)
2085118ebe8SLucas Mateus Castro (alqotel) {
2095118ebe8SLucas Mateus Castro (alqotel)     ppc6xx_tlb_t *tlb;
2105118ebe8SLucas Mateus Castro (alqotel)     int nr, best, way;
2115118ebe8SLucas Mateus Castro (alqotel)     int ret;
2125118ebe8SLucas Mateus Castro (alqotel) 
2135118ebe8SLucas Mateus Castro (alqotel)     best = -1;
2145118ebe8SLucas Mateus Castro (alqotel)     ret = -1; /* No TLB found */
2155118ebe8SLucas Mateus Castro (alqotel)     for (way = 0; way < env->nb_ways; way++) {
2165118ebe8SLucas Mateus Castro (alqotel)         nr = ppc6xx_tlb_getnum(env, eaddr, way, access_type == MMU_INST_FETCH);
2175118ebe8SLucas Mateus Castro (alqotel)         tlb = &env->tlb.tlb6[nr];
2185118ebe8SLucas Mateus Castro (alqotel)         /* This test "emulates" the PTE index match for hardware TLBs */
2195118ebe8SLucas Mateus Castro (alqotel)         if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
22056964585SCédric Le Goater             qemu_log_mask(CPU_LOG_MMU, "TLB %d/%d %s [" TARGET_FMT_lx
22156964585SCédric Le Goater                           " " TARGET_FMT_lx "] <> " TARGET_FMT_lx "\n",
22256964585SCédric Le Goater                           nr, env->nb_tlb,
2235118ebe8SLucas Mateus Castro (alqotel)                           pte_is_valid(tlb->pte0) ? "valid" : "inval",
2245118ebe8SLucas Mateus Castro (alqotel)                           tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
2255118ebe8SLucas Mateus Castro (alqotel)             continue;
2265118ebe8SLucas Mateus Castro (alqotel)         }
22756964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "TLB %d/%d %s " TARGET_FMT_lx " <> "
22856964585SCédric Le Goater                       TARGET_FMT_lx " " TARGET_FMT_lx " %c %c\n",
22956964585SCédric Le Goater                       nr, env->nb_tlb,
2305118ebe8SLucas Mateus Castro (alqotel)                       pte_is_valid(tlb->pte0) ? "valid" : "inval",
2315118ebe8SLucas Mateus Castro (alqotel)                       tlb->EPN, eaddr, tlb->pte1,
2325118ebe8SLucas Mateus Castro (alqotel)                       access_type == MMU_DATA_STORE ? 'S' : 'L',
2335118ebe8SLucas Mateus Castro (alqotel)                       access_type == MMU_INST_FETCH ? 'I' : 'D');
2345118ebe8SLucas Mateus Castro (alqotel)         switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1,
2355118ebe8SLucas Mateus Castro (alqotel)                                      0, access_type)) {
2365118ebe8SLucas Mateus Castro (alqotel)         case -2:
2375118ebe8SLucas Mateus Castro (alqotel)             /* Access violation */
2385118ebe8SLucas Mateus Castro (alqotel)             ret = -2;
2395118ebe8SLucas Mateus Castro (alqotel)             best = nr;
2405118ebe8SLucas Mateus Castro (alqotel)             break;
2410af20f35SBALATON Zoltan         case -1: /* No match */
2420af20f35SBALATON Zoltan         case -3: /* TLB inconsistency */
2435118ebe8SLucas Mateus Castro (alqotel)         default:
2445118ebe8SLucas Mateus Castro (alqotel)             break;
2455118ebe8SLucas Mateus Castro (alqotel)         case 0:
2465118ebe8SLucas Mateus Castro (alqotel)             /* access granted */
2475118ebe8SLucas Mateus Castro (alqotel)             /*
2485118ebe8SLucas Mateus Castro (alqotel)              * XXX: we should go on looping to check all TLBs
2495118ebe8SLucas Mateus Castro (alqotel)              *      consistency but we can speed-up the whole thing as
2505118ebe8SLucas Mateus Castro (alqotel)              *      the result would be undefined if TLBs are not
2515118ebe8SLucas Mateus Castro (alqotel)              *      consistent.
2525118ebe8SLucas Mateus Castro (alqotel)              */
2535118ebe8SLucas Mateus Castro (alqotel)             ret = 0;
2545118ebe8SLucas Mateus Castro (alqotel)             best = nr;
2555118ebe8SLucas Mateus Castro (alqotel)             goto done;
2565118ebe8SLucas Mateus Castro (alqotel)         }
2575118ebe8SLucas Mateus Castro (alqotel)     }
2585118ebe8SLucas Mateus Castro (alqotel)     if (best != -1) {
2595118ebe8SLucas Mateus Castro (alqotel) done:
260883f2c59SPhilippe Mathieu-Daudé         qemu_log_mask(CPU_LOG_MMU, "found TLB at addr " HWADDR_FMT_plx
26156964585SCédric Le Goater                       " prot=%01x ret=%d\n",
2625118ebe8SLucas Mateus Castro (alqotel)                       ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
2635118ebe8SLucas Mateus Castro (alqotel)         /* Update page flags */
2645118ebe8SLucas Mateus Castro (alqotel)         pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, access_type);
2655118ebe8SLucas Mateus Castro (alqotel)     }
2660af20f35SBALATON Zoltan #if defined(DUMP_PAGE_TABLES)
2670af20f35SBALATON Zoltan     if (qemu_loglevel_mask(CPU_LOG_MMU)) {
2680af20f35SBALATON Zoltan         CPUState *cs = env_cpu(env);
2690af20f35SBALATON Zoltan         hwaddr base = ppc_hash32_hpt_base(env_archcpu(env));
2700af20f35SBALATON Zoltan         hwaddr len = ppc_hash32_hpt_mask(env_archcpu(env)) + 0x80;
2710af20f35SBALATON Zoltan         uint32_t a0, a1, a2, a3;
2725118ebe8SLucas Mateus Castro (alqotel) 
2730af20f35SBALATON Zoltan         qemu_log("Page table: " HWADDR_FMT_plx " len " HWADDR_FMT_plx "\n",
2740af20f35SBALATON Zoltan                  base, len);
2750af20f35SBALATON Zoltan         for (hwaddr curaddr = base; curaddr < base + len; curaddr += 16) {
2760af20f35SBALATON Zoltan             a0 = ldl_phys(cs->as, curaddr);
2770af20f35SBALATON Zoltan             a1 = ldl_phys(cs->as, curaddr + 4);
2780af20f35SBALATON Zoltan             a2 = ldl_phys(cs->as, curaddr + 8);
2790af20f35SBALATON Zoltan             a3 = ldl_phys(cs->as, curaddr + 12);
2800af20f35SBALATON Zoltan             if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
2810af20f35SBALATON Zoltan                 qemu_log(HWADDR_FMT_plx ": %08x %08x %08x %08x\n",
2820af20f35SBALATON Zoltan                          curaddr, a0, a1, a2, a3);
2830af20f35SBALATON Zoltan             }
2840af20f35SBALATON Zoltan         }
2850af20f35SBALATON Zoltan     }
2860af20f35SBALATON Zoltan #endif
2875118ebe8SLucas Mateus Castro (alqotel)     return ret;
2885118ebe8SLucas Mateus Castro (alqotel) }
2895118ebe8SLucas Mateus Castro (alqotel) 
2905118ebe8SLucas Mateus Castro (alqotel) /* Perform BAT hit & translation */
2915118ebe8SLucas Mateus Castro (alqotel) static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
2925118ebe8SLucas Mateus Castro (alqotel)                                  int *validp, int *protp, target_ulong *BATu,
2935118ebe8SLucas Mateus Castro (alqotel)                                  target_ulong *BATl)
2945118ebe8SLucas Mateus Castro (alqotel) {
2955118ebe8SLucas Mateus Castro (alqotel)     target_ulong bl;
2965118ebe8SLucas Mateus Castro (alqotel)     int pp, valid, prot;
2975118ebe8SLucas Mateus Castro (alqotel) 
2985118ebe8SLucas Mateus Castro (alqotel)     bl = (*BATu & 0x00001FFC) << 15;
2995118ebe8SLucas Mateus Castro (alqotel)     valid = 0;
3005118ebe8SLucas Mateus Castro (alqotel)     prot = 0;
301d41ccf6eSVíctor Colombo     if ((!FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000002)) ||
302d41ccf6eSVíctor Colombo         (FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000001))) {
3035118ebe8SLucas Mateus Castro (alqotel)         valid = 1;
3045118ebe8SLucas Mateus Castro (alqotel)         pp = *BATl & 0x00000003;
3055118ebe8SLucas Mateus Castro (alqotel)         if (pp != 0) {
3065118ebe8SLucas Mateus Castro (alqotel)             prot = PAGE_READ | PAGE_EXEC;
3075118ebe8SLucas Mateus Castro (alqotel)             if (pp == 0x2) {
3085118ebe8SLucas Mateus Castro (alqotel)                 prot |= PAGE_WRITE;
3095118ebe8SLucas Mateus Castro (alqotel)             }
3105118ebe8SLucas Mateus Castro (alqotel)         }
3115118ebe8SLucas Mateus Castro (alqotel)     }
3125118ebe8SLucas Mateus Castro (alqotel)     *blp = bl;
3135118ebe8SLucas Mateus Castro (alqotel)     *validp = valid;
3145118ebe8SLucas Mateus Castro (alqotel)     *protp = prot;
3155118ebe8SLucas Mateus Castro (alqotel) }
3165118ebe8SLucas Mateus Castro (alqotel) 
3175118ebe8SLucas Mateus Castro (alqotel) static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
3185118ebe8SLucas Mateus Castro (alqotel)                            target_ulong virtual, MMUAccessType access_type)
3195118ebe8SLucas Mateus Castro (alqotel) {
3205118ebe8SLucas Mateus Castro (alqotel)     target_ulong *BATlt, *BATut, *BATu, *BATl;
3215118ebe8SLucas Mateus Castro (alqotel)     target_ulong BEPIl, BEPIu, bl;
3225118ebe8SLucas Mateus Castro (alqotel)     int i, valid, prot;
3235118ebe8SLucas Mateus Castro (alqotel)     int ret = -1;
3245118ebe8SLucas Mateus Castro (alqotel)     bool ifetch = access_type == MMU_INST_FETCH;
3255118ebe8SLucas Mateus Castro (alqotel) 
32656964585SCédric Le Goater     qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
3275118ebe8SLucas Mateus Castro (alqotel)                   ifetch ? 'I' : 'D', virtual);
3285118ebe8SLucas Mateus Castro (alqotel)     if (ifetch) {
3295118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->IBAT[1];
3305118ebe8SLucas Mateus Castro (alqotel)         BATut = env->IBAT[0];
3315118ebe8SLucas Mateus Castro (alqotel)     } else {
3325118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->DBAT[1];
3335118ebe8SLucas Mateus Castro (alqotel)         BATut = env->DBAT[0];
3345118ebe8SLucas Mateus Castro (alqotel)     }
3355118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_BATs; i++) {
3365118ebe8SLucas Mateus Castro (alqotel)         BATu = &BATut[i];
3375118ebe8SLucas Mateus Castro (alqotel)         BATl = &BATlt[i];
3385118ebe8SLucas Mateus Castro (alqotel)         BEPIu = *BATu & 0xF0000000;
3395118ebe8SLucas Mateus Castro (alqotel)         BEPIl = *BATu & 0x0FFE0000;
3405118ebe8SLucas Mateus Castro (alqotel)         bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
34156964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx " BATu "
34256964585SCédric Le Goater                       TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n", __func__,
3435118ebe8SLucas Mateus Castro (alqotel)                       ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl);
3445118ebe8SLucas Mateus Castro (alqotel)         if ((virtual & 0xF0000000) == BEPIu &&
3455118ebe8SLucas Mateus Castro (alqotel)             ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
3465118ebe8SLucas Mateus Castro (alqotel)             /* BAT matches */
3475118ebe8SLucas Mateus Castro (alqotel)             if (valid != 0) {
3485118ebe8SLucas Mateus Castro (alqotel)                 /* Get physical address */
3495118ebe8SLucas Mateus Castro (alqotel)                 ctx->raddr = (*BATl & 0xF0000000) |
3505118ebe8SLucas Mateus Castro (alqotel)                     ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
3515118ebe8SLucas Mateus Castro (alqotel)                     (virtual & 0x0001F000);
3525118ebe8SLucas Mateus Castro (alqotel)                 /* Compute access rights */
3535118ebe8SLucas Mateus Castro (alqotel)                 ctx->prot = prot;
354cd1038ecSBALATON Zoltan                 if (check_prot_access_type(ctx->prot, access_type)) {
355883f2c59SPhilippe Mathieu-Daudé                     qemu_log_mask(CPU_LOG_MMU, "BAT %d match: r " HWADDR_FMT_plx
35656964585SCédric Le Goater                                   " prot=%c%c\n", i, ctx->raddr,
35756964585SCédric Le Goater                                   ctx->prot & PAGE_READ ? 'R' : '-',
3585118ebe8SLucas Mateus Castro (alqotel)                                   ctx->prot & PAGE_WRITE ? 'W' : '-');
359cd1038ecSBALATON Zoltan                     ret = 0;
360cd1038ecSBALATON Zoltan                 } else {
361cd1038ecSBALATON Zoltan                     ret = -2;
3625118ebe8SLucas Mateus Castro (alqotel)                 }
3635118ebe8SLucas Mateus Castro (alqotel)                 break;
3645118ebe8SLucas Mateus Castro (alqotel)             }
3655118ebe8SLucas Mateus Castro (alqotel)         }
3665118ebe8SLucas Mateus Castro (alqotel)     }
3675118ebe8SLucas Mateus Castro (alqotel)     if (ret < 0) {
3685118ebe8SLucas Mateus Castro (alqotel)         if (qemu_log_enabled()) {
36956964585SCédric Le Goater             qemu_log_mask(CPU_LOG_MMU, "no BAT match for "
37056964585SCédric Le Goater                           TARGET_FMT_lx ":\n", virtual);
3715118ebe8SLucas Mateus Castro (alqotel)             for (i = 0; i < 4; i++) {
3725118ebe8SLucas Mateus Castro (alqotel)                 BATu = &BATut[i];
3735118ebe8SLucas Mateus Castro (alqotel)                 BATl = &BATlt[i];
3745118ebe8SLucas Mateus Castro (alqotel)                 BEPIu = *BATu & 0xF0000000;
3755118ebe8SLucas Mateus Castro (alqotel)                 BEPIl = *BATu & 0x0FFE0000;
3765118ebe8SLucas Mateus Castro (alqotel)                 bl = (*BATu & 0x00001FFC) << 15;
37747bededcSBALATON Zoltan                 qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx
37847bededcSBALATON Zoltan                               " BATu " TARGET_FMT_lx " BATl " TARGET_FMT_lx
37947bededcSBALATON Zoltan                               "\n\t" TARGET_FMT_lx " " TARGET_FMT_lx " "
38047bededcSBALATON Zoltan                               TARGET_FMT_lx "\n", __func__, ifetch ? 'I' : 'D',
38147bededcSBALATON Zoltan                               i, virtual, *BATu, *BATl, BEPIu, BEPIl, bl);
3825118ebe8SLucas Mateus Castro (alqotel)             }
3835118ebe8SLucas Mateus Castro (alqotel)         }
3845118ebe8SLucas Mateus Castro (alqotel)     }
3855118ebe8SLucas Mateus Castro (alqotel)     /* No hit */
3865118ebe8SLucas Mateus Castro (alqotel)     return ret;
3875118ebe8SLucas Mateus Castro (alqotel) }
3885118ebe8SLucas Mateus Castro (alqotel) 
389269d6f00SBALATON Zoltan static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
390269d6f00SBALATON Zoltan                                        target_ulong eaddr,
391269d6f00SBALATON Zoltan                                        MMUAccessType access_type, int type)
3925118ebe8SLucas Mateus Castro (alqotel) {
3935118ebe8SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = env_archcpu(env);
3945118ebe8SLucas Mateus Castro (alqotel)     hwaddr hash;
395269d6f00SBALATON Zoltan     target_ulong vsid, sr, pgidx;
396d41ccf6eSVíctor Colombo     int ds, target_page_bits;
397d41ccf6eSVíctor Colombo     bool pr;
3985118ebe8SLucas Mateus Castro (alqotel) 
399269d6f00SBALATON Zoltan     /* First try to find a BAT entry if there are any */
400269d6f00SBALATON Zoltan     if (env->nb_BATs && get_bat_6xx_tlb(env, ctx, eaddr, access_type) == 0) {
401269d6f00SBALATON Zoltan         return 0;
402269d6f00SBALATON Zoltan     }
403269d6f00SBALATON Zoltan 
404269d6f00SBALATON Zoltan     /* Perform segment based translation when no BATs matched */
405d41ccf6eSVíctor Colombo     pr = FIELD_EX64(env->msr, MSR, PR);
4065118ebe8SLucas Mateus Castro (alqotel)     ctx->eaddr = eaddr;
4075118ebe8SLucas Mateus Castro (alqotel) 
4085118ebe8SLucas Mateus Castro (alqotel)     sr = env->sr[eaddr >> 28];
409d41ccf6eSVíctor Colombo     ctx->key = (((sr & 0x20000000) && pr) ||
410d41ccf6eSVíctor Colombo                 ((sr & 0x40000000) && !pr)) ? 1 : 0;
4115118ebe8SLucas Mateus Castro (alqotel)     ds = sr & 0x80000000 ? 1 : 0;
4125118ebe8SLucas Mateus Castro (alqotel)     ctx->nx = sr & 0x10000000 ? 1 : 0;
4135118ebe8SLucas Mateus Castro (alqotel)     vsid = sr & 0x00FFFFFF;
4145118ebe8SLucas Mateus Castro (alqotel)     target_page_bits = TARGET_PAGE_BITS;
4155118ebe8SLucas Mateus Castro (alqotel)     qemu_log_mask(CPU_LOG_MMU,
4165118ebe8SLucas Mateus Castro (alqotel)                   "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
4175118ebe8SLucas Mateus Castro (alqotel)                   " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
4185118ebe8SLucas Mateus Castro (alqotel)                   " ir=%d dr=%d pr=%d %d t=%d\n",
419d41ccf6eSVíctor Colombo                   eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr,
420e4eea6efSVíctor Colombo                   (int)FIELD_EX64(env->msr, MSR, IR),
421e4eea6efSVíctor Colombo                   (int)FIELD_EX64(env->msr, MSR, DR), pr ? 1 : 0,
42256964585SCédric Le Goater                   access_type == MMU_DATA_STORE, type);
4235118ebe8SLucas Mateus Castro (alqotel)     pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
4245118ebe8SLucas Mateus Castro (alqotel)     hash = vsid ^ pgidx;
4255118ebe8SLucas Mateus Castro (alqotel)     ctx->ptem = (vsid << 7) | (pgidx >> 10);
4265118ebe8SLucas Mateus Castro (alqotel) 
42747bededcSBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "pte segment: key=%d ds %d nx %d vsid "
42847bededcSBALATON Zoltan                   TARGET_FMT_lx "\n", ctx->key, ds, ctx->nx, vsid);
4295118ebe8SLucas Mateus Castro (alqotel)     if (!ds) {
4305118ebe8SLucas Mateus Castro (alqotel)         /* Check if instruction fetch is allowed, if needed */
431f1418bdeSBALATON Zoltan         if (type == ACCESS_CODE && ctx->nx) {
432f1418bdeSBALATON Zoltan             qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
433f1418bdeSBALATON Zoltan             return -3;
434f1418bdeSBALATON Zoltan         }
4355118ebe8SLucas Mateus Castro (alqotel)         /* Page address translation */
436f1418bdeSBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx " htab_mask "
437f1418bdeSBALATON Zoltan                       HWADDR_FMT_plx " hash " HWADDR_FMT_plx "\n",
4385118ebe8SLucas Mateus Castro (alqotel)                       ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
4395118ebe8SLucas Mateus Castro (alqotel)         ctx->hash[0] = hash;
4405118ebe8SLucas Mateus Castro (alqotel)         ctx->hash[1] = ~hash;
4415118ebe8SLucas Mateus Castro (alqotel) 
4425118ebe8SLucas Mateus Castro (alqotel)         /* Initialize real address with an invalid value */
4435118ebe8SLucas Mateus Castro (alqotel)         ctx->raddr = (hwaddr)-1ULL;
4445118ebe8SLucas Mateus Castro (alqotel)         /* Software TLB search */
445f3f66a31SBALATON Zoltan         return ppc6xx_tlb_check(env, ctx, eaddr, access_type);
446f3f66a31SBALATON Zoltan     }
4475118ebe8SLucas Mateus Castro (alqotel) 
448f3f66a31SBALATON Zoltan     /* Direct-store segment : absolutely *BUGGY* for now */
449f3f66a31SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
4505118ebe8SLucas Mateus Castro (alqotel)     switch (type) {
4515118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_INT:
4525118ebe8SLucas Mateus Castro (alqotel)         /* Integer load/store : only access allowed */
4535118ebe8SLucas Mateus Castro (alqotel)         break;
4545118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_CODE:
4555118ebe8SLucas Mateus Castro (alqotel)         /* No code fetch is allowed in direct-store areas */
4565118ebe8SLucas Mateus Castro (alqotel)         return -4;
4575118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_FLOAT:
4585118ebe8SLucas Mateus Castro (alqotel)         /* Floating point load/store */
4595118ebe8SLucas Mateus Castro (alqotel)         return -4;
4605118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_RES:
4615118ebe8SLucas Mateus Castro (alqotel)         /* lwarx, ldarx or srwcx. */
4625118ebe8SLucas Mateus Castro (alqotel)         return -4;
4635118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_CACHE:
4645118ebe8SLucas Mateus Castro (alqotel)         /*
4655118ebe8SLucas Mateus Castro (alqotel)          * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
4665118ebe8SLucas Mateus Castro (alqotel)          *
4675118ebe8SLucas Mateus Castro (alqotel)          * Should make the instruction do no-op.  As it already do
4685118ebe8SLucas Mateus Castro (alqotel)          * no-op, it's quite easy :-)
4695118ebe8SLucas Mateus Castro (alqotel)          */
4705118ebe8SLucas Mateus Castro (alqotel)         ctx->raddr = eaddr;
4715118ebe8SLucas Mateus Castro (alqotel)         return 0;
4725118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_EXT:
4735118ebe8SLucas Mateus Castro (alqotel)         /* eciwx or ecowx */
4745118ebe8SLucas Mateus Castro (alqotel)         return -4;
4755118ebe8SLucas Mateus Castro (alqotel)     default:
476f3f66a31SBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need address"
477f3f66a31SBALATON Zoltan                                    " translation\n");
4785118ebe8SLucas Mateus Castro (alqotel)         return -4;
4795118ebe8SLucas Mateus Castro (alqotel)     }
4805118ebe8SLucas Mateus Castro (alqotel)     if ((access_type == MMU_DATA_STORE || ctx->key != 1) &&
4815118ebe8SLucas Mateus Castro (alqotel)         (access_type == MMU_DATA_LOAD || ctx->key != 0)) {
4825118ebe8SLucas Mateus Castro (alqotel)         ctx->raddr = eaddr;
483f3f66a31SBALATON Zoltan         return 2;
4845118ebe8SLucas Mateus Castro (alqotel)     }
485f3f66a31SBALATON Zoltan     return -2;
4865118ebe8SLucas Mateus Castro (alqotel) }
4875118ebe8SLucas Mateus Castro (alqotel) 
4885118ebe8SLucas Mateus Castro (alqotel) static const char *book3e_tsize_to_str[32] = {
4895118ebe8SLucas Mateus Castro (alqotel)     "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
4905118ebe8SLucas Mateus Castro (alqotel)     "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
4915118ebe8SLucas Mateus Castro (alqotel)     "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
4925118ebe8SLucas Mateus Castro (alqotel)     "1T", "2T"
4935118ebe8SLucas Mateus Castro (alqotel) };
4945118ebe8SLucas Mateus Castro (alqotel) 
4955118ebe8SLucas Mateus Castro (alqotel) static void mmubooke_dump_mmu(CPUPPCState *env)
4965118ebe8SLucas Mateus Castro (alqotel) {
4975118ebe8SLucas Mateus Castro (alqotel)     ppcemb_tlb_t *entry;
4985118ebe8SLucas Mateus Castro (alqotel)     int i;
4995118ebe8SLucas Mateus Castro (alqotel) 
50005739977SPhilippe Mathieu-Daudé #ifdef CONFIG_KVM
5015118ebe8SLucas Mateus Castro (alqotel)     if (kvm_enabled() && !env->kvm_sw_tlb) {
5025118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("Cannot access KVM TLB\n");
5035118ebe8SLucas Mateus Castro (alqotel)         return;
5045118ebe8SLucas Mateus Castro (alqotel)     }
50505739977SPhilippe Mathieu-Daudé #endif
5065118ebe8SLucas Mateus Castro (alqotel) 
5075118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nTLB:\n");
5085118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("Effective          Physical           Size PID   Prot     "
5095118ebe8SLucas Mateus Castro (alqotel)                 "Attr\n");
5105118ebe8SLucas Mateus Castro (alqotel) 
5115118ebe8SLucas Mateus Castro (alqotel)     entry = &env->tlb.tlbe[0];
5125118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_tlb; i++, entry++) {
5135118ebe8SLucas Mateus Castro (alqotel)         hwaddr ea, pa;
5145118ebe8SLucas Mateus Castro (alqotel)         target_ulong mask;
5155118ebe8SLucas Mateus Castro (alqotel)         uint64_t size = (uint64_t)entry->size;
5165118ebe8SLucas Mateus Castro (alqotel)         char size_buf[20];
5175118ebe8SLucas Mateus Castro (alqotel) 
5185118ebe8SLucas Mateus Castro (alqotel)         /* Check valid flag */
5195118ebe8SLucas Mateus Castro (alqotel)         if (!(entry->prot & PAGE_VALID)) {
5205118ebe8SLucas Mateus Castro (alqotel)             continue;
5215118ebe8SLucas Mateus Castro (alqotel)         }
5225118ebe8SLucas Mateus Castro (alqotel) 
5235118ebe8SLucas Mateus Castro (alqotel)         mask = ~(entry->size - 1);
5245118ebe8SLucas Mateus Castro (alqotel)         ea = entry->EPN & mask;
5255118ebe8SLucas Mateus Castro (alqotel)         pa = entry->RPN & mask;
5265118ebe8SLucas Mateus Castro (alqotel)         /* Extend the physical address to 36 bits */
5275118ebe8SLucas Mateus Castro (alqotel)         pa |= (hwaddr)(entry->RPN & 0xF) << 32;
5285118ebe8SLucas Mateus Castro (alqotel)         if (size >= 1 * MiB) {
5295118ebe8SLucas Mateus Castro (alqotel)             snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / MiB);
5305118ebe8SLucas Mateus Castro (alqotel)         } else {
5315118ebe8SLucas Mateus Castro (alqotel)             snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size / KiB);
5325118ebe8SLucas Mateus Castro (alqotel)         }
5335118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
5345118ebe8SLucas Mateus Castro (alqotel)                     (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
5355118ebe8SLucas Mateus Castro (alqotel)                     entry->prot, entry->attr);
5365118ebe8SLucas Mateus Castro (alqotel)     }
5375118ebe8SLucas Mateus Castro (alqotel) 
5385118ebe8SLucas Mateus Castro (alqotel) }
5395118ebe8SLucas Mateus Castro (alqotel) 
5405118ebe8SLucas Mateus Castro (alqotel) static void mmubooke206_dump_one_tlb(CPUPPCState *env, int tlbn, int offset,
5415118ebe8SLucas Mateus Castro (alqotel)                                      int tlbsize)
5425118ebe8SLucas Mateus Castro (alqotel) {
5435118ebe8SLucas Mateus Castro (alqotel)     ppcmas_tlb_t *entry;
5445118ebe8SLucas Mateus Castro (alqotel)     int i;
5455118ebe8SLucas Mateus Castro (alqotel) 
5465118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nTLB%d:\n", tlbn);
5475118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("Effective          Physical           Size TID   TS SRWX"
5485118ebe8SLucas Mateus Castro (alqotel)                 " URWX WIMGE U0123\n");
5495118ebe8SLucas Mateus Castro (alqotel) 
5505118ebe8SLucas Mateus Castro (alqotel)     entry = &env->tlb.tlbm[offset];
5515118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < tlbsize; i++, entry++) {
5525118ebe8SLucas Mateus Castro (alqotel)         hwaddr ea, pa, size;
5535118ebe8SLucas Mateus Castro (alqotel)         int tsize;
5545118ebe8SLucas Mateus Castro (alqotel) 
5555118ebe8SLucas Mateus Castro (alqotel)         if (!(entry->mas1 & MAS1_VALID)) {
5565118ebe8SLucas Mateus Castro (alqotel)             continue;
5575118ebe8SLucas Mateus Castro (alqotel)         }
5585118ebe8SLucas Mateus Castro (alqotel) 
5595118ebe8SLucas Mateus Castro (alqotel)         tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
5605118ebe8SLucas Mateus Castro (alqotel)         size = 1024ULL << tsize;
5615118ebe8SLucas Mateus Castro (alqotel)         ea = entry->mas2 & ~(size - 1);
5625118ebe8SLucas Mateus Castro (alqotel)         pa = entry->mas7_3 & ~(size - 1);
5635118ebe8SLucas Mateus Castro (alqotel) 
5645118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u  S%c%c%c"
5655118ebe8SLucas Mateus Castro (alqotel)                     " U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
5665118ebe8SLucas Mateus Castro (alqotel)                     (uint64_t)ea, (uint64_t)pa,
5675118ebe8SLucas Mateus Castro (alqotel)                     book3e_tsize_to_str[tsize],
5685118ebe8SLucas Mateus Castro (alqotel)                     (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
5695118ebe8SLucas Mateus Castro (alqotel)                     (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
5705118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_SR ? 'R' : '-',
5715118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_SW ? 'W' : '-',
5725118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_SX ? 'X' : '-',
5735118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_UR ? 'R' : '-',
5745118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_UW ? 'W' : '-',
5755118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_UX ? 'X' : '-',
5765118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_W ? 'W' : '-',
5775118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_I ? 'I' : '-',
5785118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_M ? 'M' : '-',
5795118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_G ? 'G' : '-',
5805118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_E ? 'E' : '-',
5815118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U0 ? '0' : '-',
5825118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U1 ? '1' : '-',
5835118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U2 ? '2' : '-',
5845118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U3 ? '3' : '-');
5855118ebe8SLucas Mateus Castro (alqotel)     }
5865118ebe8SLucas Mateus Castro (alqotel) }
5875118ebe8SLucas Mateus Castro (alqotel) 
5885118ebe8SLucas Mateus Castro (alqotel) static void mmubooke206_dump_mmu(CPUPPCState *env)
5895118ebe8SLucas Mateus Castro (alqotel) {
5905118ebe8SLucas Mateus Castro (alqotel)     int offset = 0;
5915118ebe8SLucas Mateus Castro (alqotel)     int i;
5925118ebe8SLucas Mateus Castro (alqotel) 
59305739977SPhilippe Mathieu-Daudé #ifdef CONFIG_KVM
5945118ebe8SLucas Mateus Castro (alqotel)     if (kvm_enabled() && !env->kvm_sw_tlb) {
5955118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("Cannot access KVM TLB\n");
5965118ebe8SLucas Mateus Castro (alqotel)         return;
5975118ebe8SLucas Mateus Castro (alqotel)     }
59805739977SPhilippe Mathieu-Daudé #endif
5995118ebe8SLucas Mateus Castro (alqotel) 
6005118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
6015118ebe8SLucas Mateus Castro (alqotel)         int size = booke206_tlb_size(env, i);
6025118ebe8SLucas Mateus Castro (alqotel) 
6035118ebe8SLucas Mateus Castro (alqotel)         if (size == 0) {
6045118ebe8SLucas Mateus Castro (alqotel)             continue;
6055118ebe8SLucas Mateus Castro (alqotel)         }
6065118ebe8SLucas Mateus Castro (alqotel) 
6075118ebe8SLucas Mateus Castro (alqotel)         mmubooke206_dump_one_tlb(env, i, offset, size);
6085118ebe8SLucas Mateus Castro (alqotel)         offset += size;
6095118ebe8SLucas Mateus Castro (alqotel)     }
6105118ebe8SLucas Mateus Castro (alqotel) }
6115118ebe8SLucas Mateus Castro (alqotel) 
6125118ebe8SLucas Mateus Castro (alqotel) static void mmu6xx_dump_BATs(CPUPPCState *env, int type)
6135118ebe8SLucas Mateus Castro (alqotel) {
6145118ebe8SLucas Mateus Castro (alqotel)     target_ulong *BATlt, *BATut, *BATu, *BATl;
6155118ebe8SLucas Mateus Castro (alqotel)     target_ulong BEPIl, BEPIu, bl;
6165118ebe8SLucas Mateus Castro (alqotel)     int i;
6175118ebe8SLucas Mateus Castro (alqotel) 
6185118ebe8SLucas Mateus Castro (alqotel)     switch (type) {
6195118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_CODE:
6205118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->IBAT[1];
6215118ebe8SLucas Mateus Castro (alqotel)         BATut = env->IBAT[0];
6225118ebe8SLucas Mateus Castro (alqotel)         break;
6235118ebe8SLucas Mateus Castro (alqotel)     default:
6245118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->DBAT[1];
6255118ebe8SLucas Mateus Castro (alqotel)         BATut = env->DBAT[0];
6265118ebe8SLucas Mateus Castro (alqotel)         break;
6275118ebe8SLucas Mateus Castro (alqotel)     }
6285118ebe8SLucas Mateus Castro (alqotel) 
6295118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_BATs; i++) {
6305118ebe8SLucas Mateus Castro (alqotel)         BATu = &BATut[i];
6315118ebe8SLucas Mateus Castro (alqotel)         BATl = &BATlt[i];
6325118ebe8SLucas Mateus Castro (alqotel)         BEPIu = *BATu & 0xF0000000;
6335118ebe8SLucas Mateus Castro (alqotel)         BEPIl = *BATu & 0x0FFE0000;
6345118ebe8SLucas Mateus Castro (alqotel)         bl = (*BATu & 0x00001FFC) << 15;
6355118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("%s BAT%d BATu " TARGET_FMT_lx
6365118ebe8SLucas Mateus Castro (alqotel)                     " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
6375118ebe8SLucas Mateus Castro (alqotel)                     TARGET_FMT_lx " " TARGET_FMT_lx "\n",
6385118ebe8SLucas Mateus Castro (alqotel)                     type == ACCESS_CODE ? "code" : "data", i,
6395118ebe8SLucas Mateus Castro (alqotel)                     *BATu, *BATl, BEPIu, BEPIl, bl);
6405118ebe8SLucas Mateus Castro (alqotel)     }
6415118ebe8SLucas Mateus Castro (alqotel) }
6425118ebe8SLucas Mateus Castro (alqotel) 
6435118ebe8SLucas Mateus Castro (alqotel) static void mmu6xx_dump_mmu(CPUPPCState *env)
6445118ebe8SLucas Mateus Castro (alqotel) {
6455118ebe8SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = env_archcpu(env);
6465118ebe8SLucas Mateus Castro (alqotel)     ppc6xx_tlb_t *tlb;
6475118ebe8SLucas Mateus Castro (alqotel)     target_ulong sr;
6485118ebe8SLucas Mateus Castro (alqotel)     int type, way, entry, i;
6495118ebe8SLucas Mateus Castro (alqotel) 
6505118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu));
6515118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu));
6525118ebe8SLucas Mateus Castro (alqotel) 
6535118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nSegment registers:\n");
6545118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < 32; i++) {
6555118ebe8SLucas Mateus Castro (alqotel)         sr = env->sr[i];
6565118ebe8SLucas Mateus Castro (alqotel)         if (sr & 0x80000000) {
6575118ebe8SLucas Mateus Castro (alqotel)             qemu_printf("%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
6585118ebe8SLucas Mateus Castro (alqotel)                         "CNTLR_SPEC=0x%05x\n", i,
6595118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
6605118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
6615118ebe8SLucas Mateus Castro (alqotel)                         (uint32_t)(sr & 0xFFFFF));
6625118ebe8SLucas Mateus Castro (alqotel)         } else {
6635118ebe8SLucas Mateus Castro (alqotel)             qemu_printf("%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
6645118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
6655118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
6665118ebe8SLucas Mateus Castro (alqotel)                         (uint32_t)(sr & 0x00FFFFFF));
6675118ebe8SLucas Mateus Castro (alqotel)         }
6685118ebe8SLucas Mateus Castro (alqotel)     }
6695118ebe8SLucas Mateus Castro (alqotel) 
6705118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nBATs:\n");
6715118ebe8SLucas Mateus Castro (alqotel)     mmu6xx_dump_BATs(env, ACCESS_INT);
6725118ebe8SLucas Mateus Castro (alqotel)     mmu6xx_dump_BATs(env, ACCESS_CODE);
6735118ebe8SLucas Mateus Castro (alqotel) 
6745118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nTLBs                       [EPN    EPN + SIZE]\n");
6755118ebe8SLucas Mateus Castro (alqotel)     for (type = 0; type < 2; type++) {
6765118ebe8SLucas Mateus Castro (alqotel)         for (way = 0; way < env->nb_ways; way++) {
6775118ebe8SLucas Mateus Castro (alqotel)             for (entry = env->nb_tlb * type + env->tlb_per_way * way;
6785118ebe8SLucas Mateus Castro (alqotel)                  entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
6795118ebe8SLucas Mateus Castro (alqotel)                  entry++) {
6805118ebe8SLucas Mateus Castro (alqotel) 
6815118ebe8SLucas Mateus Castro (alqotel)                 tlb = &env->tlb.tlb6[entry];
6825118ebe8SLucas Mateus Castro (alqotel)                 qemu_printf("%s TLB %02d/%02d way:%d %s ["
6835118ebe8SLucas Mateus Castro (alqotel)                             TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
6845118ebe8SLucas Mateus Castro (alqotel)                             type ? "code" : "data", entry % env->nb_tlb,
6855118ebe8SLucas Mateus Castro (alqotel)                             env->nb_tlb, way,
6865118ebe8SLucas Mateus Castro (alqotel)                             pte_is_valid(tlb->pte0) ? "valid" : "inval",
6875118ebe8SLucas Mateus Castro (alqotel)                             tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
6885118ebe8SLucas Mateus Castro (alqotel)             }
6895118ebe8SLucas Mateus Castro (alqotel)         }
6905118ebe8SLucas Mateus Castro (alqotel)     }
6915118ebe8SLucas Mateus Castro (alqotel) }
6925118ebe8SLucas Mateus Castro (alqotel) 
6935118ebe8SLucas Mateus Castro (alqotel) void dump_mmu(CPUPPCState *env)
6945118ebe8SLucas Mateus Castro (alqotel) {
6955118ebe8SLucas Mateus Castro (alqotel)     switch (env->mmu_model) {
6965118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_BOOKE:
6975118ebe8SLucas Mateus Castro (alqotel)         mmubooke_dump_mmu(env);
6985118ebe8SLucas Mateus Castro (alqotel)         break;
6995118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_BOOKE206:
7005118ebe8SLucas Mateus Castro (alqotel)         mmubooke206_dump_mmu(env);
7015118ebe8SLucas Mateus Castro (alqotel)         break;
7025118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_SOFT_6xx:
7035118ebe8SLucas Mateus Castro (alqotel)         mmu6xx_dump_mmu(env);
7045118ebe8SLucas Mateus Castro (alqotel)         break;
7055118ebe8SLucas Mateus Castro (alqotel) #if defined(TARGET_PPC64)
7065118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_64B:
7075118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_03:
7085118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_06:
7095118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_07:
7105118ebe8SLucas Mateus Castro (alqotel)         dump_slb(env_archcpu(env));
7115118ebe8SLucas Mateus Castro (alqotel)         break;
7125118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_3_00:
7135118ebe8SLucas Mateus Castro (alqotel)         if (ppc64_v3_radix(env_archcpu(env))) {
7145118ebe8SLucas Mateus Castro (alqotel)             qemu_log_mask(LOG_UNIMP, "%s: the PPC64 MMU is unsupported\n",
7155118ebe8SLucas Mateus Castro (alqotel)                           __func__);
7165118ebe8SLucas Mateus Castro (alqotel)         } else {
7175118ebe8SLucas Mateus Castro (alqotel)             dump_slb(env_archcpu(env));
7185118ebe8SLucas Mateus Castro (alqotel)         }
7195118ebe8SLucas Mateus Castro (alqotel)         break;
7205118ebe8SLucas Mateus Castro (alqotel) #endif
7215118ebe8SLucas Mateus Castro (alqotel)     default:
7225118ebe8SLucas Mateus Castro (alqotel)         qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
7235118ebe8SLucas Mateus Castro (alqotel)     }
7245118ebe8SLucas Mateus Castro (alqotel) }
7255118ebe8SLucas Mateus Castro (alqotel) 
726ba91e5d0SBALATON Zoltan 
727c29f808aSBALATON Zoltan static bool ppc_real_mode_xlate(PowerPCCPU *cpu, vaddr eaddr,
728c29f808aSBALATON Zoltan                                 MMUAccessType access_type,
729c29f808aSBALATON Zoltan                                 hwaddr *raddrp, int *psizep, int *protp)
730c29f808aSBALATON Zoltan {
731c29f808aSBALATON Zoltan     CPUPPCState *env = &cpu->env;
732c29f808aSBALATON Zoltan 
733c29f808aSBALATON Zoltan     if (access_type == MMU_INST_FETCH ? !FIELD_EX64(env->msr, MSR, IR)
734c29f808aSBALATON Zoltan                                       : !FIELD_EX64(env->msr, MSR, DR)) {
735c29f808aSBALATON Zoltan         *raddrp = eaddr;
736c29f808aSBALATON Zoltan         *protp = PAGE_RWX;
737c29f808aSBALATON Zoltan         *psizep = TARGET_PAGE_BITS;
738c29f808aSBALATON Zoltan         return true;
739c29f808aSBALATON Zoltan     } else if (env->mmu_model == POWERPC_MMU_REAL) {
740c29f808aSBALATON Zoltan         cpu_abort(CPU(cpu), "PowerPC in real mode shold not do translation\n");
741c29f808aSBALATON Zoltan     }
742c29f808aSBALATON Zoltan     return false;
743c29f808aSBALATON Zoltan }
744c29f808aSBALATON Zoltan 
74558b01325SBALATON Zoltan static bool ppc_40x_xlate(PowerPCCPU *cpu, vaddr eaddr,
74658b01325SBALATON Zoltan                           MMUAccessType access_type,
74758b01325SBALATON Zoltan                           hwaddr *raddrp, int *psizep, int *protp,
74858b01325SBALATON Zoltan                           int mmu_idx, bool guest_visible)
74958b01325SBALATON Zoltan {
75058b01325SBALATON Zoltan     CPUState *cs = CPU(cpu);
75158b01325SBALATON Zoltan     CPUPPCState *env = &cpu->env;
75258b01325SBALATON Zoltan     int ret;
75358b01325SBALATON Zoltan 
75458b01325SBALATON Zoltan     if (ppc_real_mode_xlate(cpu, eaddr, access_type, raddrp, psizep, protp)) {
75558b01325SBALATON Zoltan         return true;
75658b01325SBALATON Zoltan     }
75758b01325SBALATON Zoltan 
75858b01325SBALATON Zoltan     ret = mmu40x_get_physical_address(env, raddrp, protp, eaddr, access_type);
75958b01325SBALATON Zoltan     if (ret == 0) {
76058b01325SBALATON Zoltan         *psizep = TARGET_PAGE_BITS;
76158b01325SBALATON Zoltan         return true;
76258b01325SBALATON Zoltan     } else if (!guest_visible) {
76358b01325SBALATON Zoltan         return false;
76458b01325SBALATON Zoltan     }
76558b01325SBALATON Zoltan 
76658b01325SBALATON Zoltan     log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
76758b01325SBALATON Zoltan     if (access_type == MMU_INST_FETCH) {
76858b01325SBALATON Zoltan         switch (ret) {
76958b01325SBALATON Zoltan         case -1:
77058b01325SBALATON Zoltan             /* No matches in page tables or TLB */
77158b01325SBALATON Zoltan             cs->exception_index = POWERPC_EXCP_ITLB;
77258b01325SBALATON Zoltan             env->error_code = 0;
77358b01325SBALATON Zoltan             env->spr[SPR_40x_DEAR] = eaddr;
77458b01325SBALATON Zoltan             env->spr[SPR_40x_ESR] = 0x00000000;
77558b01325SBALATON Zoltan             break;
77658b01325SBALATON Zoltan         case -2:
77758b01325SBALATON Zoltan             /* Access rights violation */
77858b01325SBALATON Zoltan             cs->exception_index = POWERPC_EXCP_ISI;
77958b01325SBALATON Zoltan             env->error_code = 0x08000000;
78058b01325SBALATON Zoltan             break;
78158b01325SBALATON Zoltan         default:
78258b01325SBALATON Zoltan             g_assert_not_reached();
78358b01325SBALATON Zoltan         }
78458b01325SBALATON Zoltan     } else {
78558b01325SBALATON Zoltan         switch (ret) {
78658b01325SBALATON Zoltan         case -1:
78758b01325SBALATON Zoltan             /* No matches in page tables or TLB */
78858b01325SBALATON Zoltan             cs->exception_index = POWERPC_EXCP_DTLB;
78958b01325SBALATON Zoltan             env->error_code = 0;
79058b01325SBALATON Zoltan             env->spr[SPR_40x_DEAR] = eaddr;
79158b01325SBALATON Zoltan             if (access_type == MMU_DATA_STORE) {
79258b01325SBALATON Zoltan                 env->spr[SPR_40x_ESR] = 0x00800000;
79358b01325SBALATON Zoltan             } else {
79458b01325SBALATON Zoltan                 env->spr[SPR_40x_ESR] = 0x00000000;
79558b01325SBALATON Zoltan             }
79658b01325SBALATON Zoltan             break;
79758b01325SBALATON Zoltan         case -2:
79858b01325SBALATON Zoltan             /* Access rights violation */
79958b01325SBALATON Zoltan             cs->exception_index = POWERPC_EXCP_DSI;
80058b01325SBALATON Zoltan             env->error_code = 0;
80158b01325SBALATON Zoltan             env->spr[SPR_40x_DEAR] = eaddr;
80258b01325SBALATON Zoltan             if (access_type == MMU_DATA_STORE) {
80358b01325SBALATON Zoltan                 env->spr[SPR_40x_ESR] |= 0x00800000;
80458b01325SBALATON Zoltan             }
80558b01325SBALATON Zoltan             break;
80658b01325SBALATON Zoltan         default:
80758b01325SBALATON Zoltan             g_assert_not_reached();
80858b01325SBALATON Zoltan         }
80958b01325SBALATON Zoltan     }
81058b01325SBALATON Zoltan     return false;
81158b01325SBALATON Zoltan }
81258b01325SBALATON Zoltan 
8136b9ea7f3SBALATON Zoltan static bool ppc_6xx_xlate(PowerPCCPU *cpu, vaddr eaddr,
8145118ebe8SLucas Mateus Castro (alqotel)                           MMUAccessType access_type,
8155118ebe8SLucas Mateus Castro (alqotel)                           hwaddr *raddrp, int *psizep, int *protp,
8165118ebe8SLucas Mateus Castro (alqotel)                           int mmu_idx, bool guest_visible)
8175118ebe8SLucas Mateus Castro (alqotel) {
8185118ebe8SLucas Mateus Castro (alqotel)     CPUState *cs = CPU(cpu);
8195118ebe8SLucas Mateus Castro (alqotel)     CPUPPCState *env = &cpu->env;
8205118ebe8SLucas Mateus Castro (alqotel)     mmu_ctx_t ctx;
8215118ebe8SLucas Mateus Castro (alqotel)     int type;
8225118ebe8SLucas Mateus Castro (alqotel)     int ret;
8235118ebe8SLucas Mateus Castro (alqotel) 
824c29f808aSBALATON Zoltan     if (ppc_real_mode_xlate(cpu, eaddr, access_type, raddrp, psizep, protp)) {
825c29f808aSBALATON Zoltan         return true;
826c29f808aSBALATON Zoltan     }
827c29f808aSBALATON Zoltan 
8285118ebe8SLucas Mateus Castro (alqotel)     if (access_type == MMU_INST_FETCH) {
8295118ebe8SLucas Mateus Castro (alqotel)         /* code access */
8305118ebe8SLucas Mateus Castro (alqotel)         type = ACCESS_CODE;
8315118ebe8SLucas Mateus Castro (alqotel)     } else if (guest_visible) {
8325118ebe8SLucas Mateus Castro (alqotel)         /* data access */
8335118ebe8SLucas Mateus Castro (alqotel)         type = env->access_type;
8345118ebe8SLucas Mateus Castro (alqotel)     } else {
8355118ebe8SLucas Mateus Castro (alqotel)         type = ACCESS_INT;
8365118ebe8SLucas Mateus Castro (alqotel)     }
8375118ebe8SLucas Mateus Castro (alqotel) 
8386b9ea7f3SBALATON Zoltan     ctx.prot = 0;
8396b9ea7f3SBALATON Zoltan     ctx.hash[0] = 0;
8406b9ea7f3SBALATON Zoltan     ctx.hash[1] = 0;
8416b9ea7f3SBALATON Zoltan     ret = mmu6xx_get_physical_address(env, &ctx, eaddr, access_type, type);
8425118ebe8SLucas Mateus Castro (alqotel)     if (ret == 0) {
8435118ebe8SLucas Mateus Castro (alqotel)         *raddrp = ctx.raddr;
8445118ebe8SLucas Mateus Castro (alqotel)         *protp = ctx.prot;
8455118ebe8SLucas Mateus Castro (alqotel)         *psizep = TARGET_PAGE_BITS;
8465118ebe8SLucas Mateus Castro (alqotel)         return true;
8479e9ca54cSBALATON Zoltan     } else if (!guest_visible) {
8489e9ca54cSBALATON Zoltan         return false;
8495118ebe8SLucas Mateus Castro (alqotel)     }
8505118ebe8SLucas Mateus Castro (alqotel) 
85156964585SCédric Le Goater     log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
8525118ebe8SLucas Mateus Castro (alqotel)     if (type == ACCESS_CODE) {
8535118ebe8SLucas Mateus Castro (alqotel)         switch (ret) {
8545118ebe8SLucas Mateus Castro (alqotel)         case -1:
8555118ebe8SLucas Mateus Castro (alqotel)             /* No matches in page tables or TLB */
8565118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_IFTLB;
8575118ebe8SLucas Mateus Castro (alqotel)             env->error_code = 1 << 18;
8585118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_IMISS] = eaddr;
8595118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
8605118ebe8SLucas Mateus Castro (alqotel)             goto tlb_miss;
8615118ebe8SLucas Mateus Castro (alqotel)         case -2:
8625118ebe8SLucas Mateus Castro (alqotel)             /* Access rights violation */
8635118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_ISI;
8645118ebe8SLucas Mateus Castro (alqotel)             env->error_code = 0x08000000;
8655118ebe8SLucas Mateus Castro (alqotel)             break;
8665118ebe8SLucas Mateus Castro (alqotel)         case -3:
8675118ebe8SLucas Mateus Castro (alqotel)             /* No execute protection violation */
8685118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_ISI;
869ba91e5d0SBALATON Zoltan             env->error_code = 0x10000000;
8705118ebe8SLucas Mateus Castro (alqotel)             break;
8715118ebe8SLucas Mateus Castro (alqotel)         case -4:
8725118ebe8SLucas Mateus Castro (alqotel)             /* Direct store exception */
8735118ebe8SLucas Mateus Castro (alqotel)             /* No code fetch is allowed in direct-store areas */
8745118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_ISI;
8755118ebe8SLucas Mateus Castro (alqotel)             env->error_code = 0x10000000;
8765118ebe8SLucas Mateus Castro (alqotel)             break;
8775118ebe8SLucas Mateus Castro (alqotel)         }
8785118ebe8SLucas Mateus Castro (alqotel)     } else {
8795118ebe8SLucas Mateus Castro (alqotel)         switch (ret) {
8805118ebe8SLucas Mateus Castro (alqotel)         case -1:
8815118ebe8SLucas Mateus Castro (alqotel)             /* No matches in page tables or TLB */
8825118ebe8SLucas Mateus Castro (alqotel)             if (access_type == MMU_DATA_STORE) {
8835118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DSTLB;
8845118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 1 << 16;
8855118ebe8SLucas Mateus Castro (alqotel)             } else {
8865118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DLTLB;
8875118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 0;
8885118ebe8SLucas Mateus Castro (alqotel)             }
8895118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_DMISS] = eaddr;
8905118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
8915118ebe8SLucas Mateus Castro (alqotel) tlb_miss:
8925118ebe8SLucas Mateus Castro (alqotel)             env->error_code |= ctx.key << 19;
8935118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
8945118ebe8SLucas Mateus Castro (alqotel)                                   get_pteg_offset32(cpu, ctx.hash[0]);
8955118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
8965118ebe8SLucas Mateus Castro (alqotel)                                   get_pteg_offset32(cpu, ctx.hash[1]);
8975118ebe8SLucas Mateus Castro (alqotel)             break;
8985118ebe8SLucas Mateus Castro (alqotel)         case -2:
8995118ebe8SLucas Mateus Castro (alqotel)             /* Access rights violation */
9005118ebe8SLucas Mateus Castro (alqotel)             cs->exception_index = POWERPC_EXCP_DSI;
9015118ebe8SLucas Mateus Castro (alqotel)             env->error_code = 0;
9025118ebe8SLucas Mateus Castro (alqotel)             env->spr[SPR_DAR] = eaddr;
9035118ebe8SLucas Mateus Castro (alqotel)             if (access_type == MMU_DATA_STORE) {
9045118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DSISR] = 0x0A000000;
9055118ebe8SLucas Mateus Castro (alqotel)             } else {
9065118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DSISR] = 0x08000000;
9075118ebe8SLucas Mateus Castro (alqotel)             }
9085118ebe8SLucas Mateus Castro (alqotel)             break;
9095118ebe8SLucas Mateus Castro (alqotel)         case -4:
9105118ebe8SLucas Mateus Castro (alqotel)             /* Direct store exception */
9115118ebe8SLucas Mateus Castro (alqotel)             switch (type) {
9125118ebe8SLucas Mateus Castro (alqotel)             case ACCESS_FLOAT:
9135118ebe8SLucas Mateus Castro (alqotel)                 /* Floating point load/store */
9145118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_ALIGN;
9155118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = POWERPC_EXCP_ALIGN_FP;
9165118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DAR] = eaddr;
9175118ebe8SLucas Mateus Castro (alqotel)                 break;
9185118ebe8SLucas Mateus Castro (alqotel)             case ACCESS_RES:
9195118ebe8SLucas Mateus Castro (alqotel)                 /* lwarx, ldarx or stwcx. */
9205118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DSI;
9215118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 0;
9225118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DAR] = eaddr;
9235118ebe8SLucas Mateus Castro (alqotel)                 if (access_type == MMU_DATA_STORE) {
9245118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DSISR] = 0x06000000;
9255118ebe8SLucas Mateus Castro (alqotel)                 } else {
9265118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DSISR] = 0x04000000;
9275118ebe8SLucas Mateus Castro (alqotel)                 }
9285118ebe8SLucas Mateus Castro (alqotel)                 break;
9295118ebe8SLucas Mateus Castro (alqotel)             case ACCESS_EXT:
9305118ebe8SLucas Mateus Castro (alqotel)                 /* eciwx or ecowx */
9315118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DSI;
9325118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 0;
9335118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DAR] = eaddr;
9345118ebe8SLucas Mateus Castro (alqotel)                 if (access_type == MMU_DATA_STORE) {
9355118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DSISR] = 0x06100000;
9365118ebe8SLucas Mateus Castro (alqotel)                 } else {
9375118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DSISR] = 0x04100000;
9385118ebe8SLucas Mateus Castro (alqotel)                 }
9395118ebe8SLucas Mateus Castro (alqotel)                 break;
9405118ebe8SLucas Mateus Castro (alqotel)             default:
9415118ebe8SLucas Mateus Castro (alqotel)                 printf("DSI: invalid exception (%d)\n", ret);
9425118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_PROGRAM;
9439e9ca54cSBALATON Zoltan                 env->error_code = POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
9445118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_DAR] = eaddr;
9455118ebe8SLucas Mateus Castro (alqotel)                 break;
9465118ebe8SLucas Mateus Castro (alqotel)             }
9475118ebe8SLucas Mateus Castro (alqotel)             break;
9485118ebe8SLucas Mateus Castro (alqotel)         }
9495118ebe8SLucas Mateus Castro (alqotel)     }
9505118ebe8SLucas Mateus Castro (alqotel)     return false;
9515118ebe8SLucas Mateus Castro (alqotel) }
9525118ebe8SLucas Mateus Castro (alqotel) 
9535118ebe8SLucas Mateus Castro (alqotel) /*****************************************************************************/
9545118ebe8SLucas Mateus Castro (alqotel) 
9555118ebe8SLucas Mateus Castro (alqotel) bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
9565118ebe8SLucas Mateus Castro (alqotel)                       hwaddr *raddrp, int *psizep, int *protp,
9575118ebe8SLucas Mateus Castro (alqotel)                       int mmu_idx, bool guest_visible)
9585118ebe8SLucas Mateus Castro (alqotel) {
9595118ebe8SLucas Mateus Castro (alqotel)     switch (cpu->env.mmu_model) {
9605118ebe8SLucas Mateus Castro (alqotel) #if defined(TARGET_PPC64)
9615118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_3_00:
9625118ebe8SLucas Mateus Castro (alqotel)         if (ppc64_v3_radix(cpu)) {
9635118ebe8SLucas Mateus Castro (alqotel)             return ppc_radix64_xlate(cpu, eaddr, access_type, raddrp,
9645118ebe8SLucas Mateus Castro (alqotel)                                      psizep, protp, mmu_idx, guest_visible);
9655118ebe8SLucas Mateus Castro (alqotel)         }
9665118ebe8SLucas Mateus Castro (alqotel)         /* fall through */
9675118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_64B:
9685118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_03:
9695118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_06:
9705118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_07:
9715118ebe8SLucas Mateus Castro (alqotel)         return ppc_hash64_xlate(cpu, eaddr, access_type,
9725118ebe8SLucas Mateus Castro (alqotel)                                 raddrp, psizep, protp, mmu_idx, guest_visible);
9735118ebe8SLucas Mateus Castro (alqotel) #endif
9745118ebe8SLucas Mateus Castro (alqotel) 
9755118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_32B:
9765118ebe8SLucas Mateus Castro (alqotel)         return ppc_hash32_xlate(cpu, eaddr, access_type, raddrp,
9775118ebe8SLucas Mateus Castro (alqotel)                                psizep, protp, mmu_idx, guest_visible);
978ba91e5d0SBALATON Zoltan     case POWERPC_MMU_BOOKE:
979ba91e5d0SBALATON Zoltan     case POWERPC_MMU_BOOKE206:
980ba91e5d0SBALATON Zoltan         return ppc_booke_xlate(cpu, eaddr, access_type, raddrp,
981ba91e5d0SBALATON Zoltan                                psizep, protp, mmu_idx, guest_visible);
98258b01325SBALATON Zoltan     case POWERPC_MMU_SOFT_4xx:
98358b01325SBALATON Zoltan         return ppc_40x_xlate(cpu, eaddr, access_type, raddrp,
98458b01325SBALATON Zoltan                              psizep, protp, mmu_idx, guest_visible);
9856b9ea7f3SBALATON Zoltan     case POWERPC_MMU_SOFT_6xx:
9866b9ea7f3SBALATON Zoltan         return ppc_6xx_xlate(cpu, eaddr, access_type, raddrp,
9876b9ea7f3SBALATON Zoltan                              psizep, protp, mmu_idx, guest_visible);
988c29f808aSBALATON Zoltan     case POWERPC_MMU_REAL:
989c29f808aSBALATON Zoltan         return ppc_real_mode_xlate(cpu, eaddr, access_type, raddrp, psizep,
990c29f808aSBALATON Zoltan                                    protp);
991cfd5c128SBALATON Zoltan     case POWERPC_MMU_MPC8xx:
992cfd5c128SBALATON Zoltan         cpu_abort(env_cpu(&cpu->env), "MPC8xx MMU model is not implemented\n");
9935118ebe8SLucas Mateus Castro (alqotel)     default:
9946b9ea7f3SBALATON Zoltan         cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
9955118ebe8SLucas Mateus Castro (alqotel)     }
9965118ebe8SLucas Mateus Castro (alqotel) }
9975118ebe8SLucas Mateus Castro (alqotel) 
9985118ebe8SLucas Mateus Castro (alqotel) hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
9995118ebe8SLucas Mateus Castro (alqotel) {
10005118ebe8SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = POWERPC_CPU(cs);
10015118ebe8SLucas Mateus Castro (alqotel)     hwaddr raddr;
10025118ebe8SLucas Mateus Castro (alqotel)     int s, p;
10035118ebe8SLucas Mateus Castro (alqotel) 
10045118ebe8SLucas Mateus Castro (alqotel)     /*
10055118ebe8SLucas Mateus Castro (alqotel)      * Some MMUs have separate TLBs for code and data. If we only
10065118ebe8SLucas Mateus Castro (alqotel)      * try an MMU_DATA_LOAD, we may not be able to read instructions
10075118ebe8SLucas Mateus Castro (alqotel)      * mapped by code TLBs, so we also try a MMU_INST_FETCH.
10085118ebe8SLucas Mateus Castro (alqotel)      */
10095118ebe8SLucas Mateus Castro (alqotel)     if (ppc_xlate(cpu, addr, MMU_DATA_LOAD, &raddr, &s, &p,
1010fb00f730SRichard Henderson                   ppc_env_mmu_index(&cpu->env, false), false) ||
10115118ebe8SLucas Mateus Castro (alqotel)         ppc_xlate(cpu, addr, MMU_INST_FETCH, &raddr, &s, &p,
1012fb00f730SRichard Henderson                   ppc_env_mmu_index(&cpu->env, true), false)) {
10135118ebe8SLucas Mateus Castro (alqotel)         return raddr & TARGET_PAGE_MASK;
10145118ebe8SLucas Mateus Castro (alqotel)     }
10155118ebe8SLucas Mateus Castro (alqotel)     return -1;
10165118ebe8SLucas Mateus Castro (alqotel) }
1017