xref: /openbmc/qemu/target/ppc/mmu_common.c (revision fb00f730c5eb05b3c54da8b1f805008ca38672ea)
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"
285118ebe8SLucas Mateus Castro (alqotel) #include "exec/log.h"
295118ebe8SLucas Mateus Castro (alqotel) #include "helper_regs.h"
305118ebe8SLucas Mateus Castro (alqotel) #include "qemu/error-report.h"
315118ebe8SLucas Mateus Castro (alqotel) #include "qemu/qemu-print.h"
325118ebe8SLucas Mateus Castro (alqotel) #include "internal.h"
335118ebe8SLucas Mateus Castro (alqotel) #include "mmu-book3s-v3.h"
345118ebe8SLucas Mateus Castro (alqotel) #include "mmu-radix64.h"
355118ebe8SLucas Mateus Castro (alqotel) 
365118ebe8SLucas Mateus Castro (alqotel) /* #define DUMP_PAGE_TABLES */
375118ebe8SLucas Mateus Castro (alqotel) 
38d6ae8ec6SLucas Mateus Castro (alqotel) void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
39d6ae8ec6SLucas Mateus Castro (alqotel) {
40d6ae8ec6SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = env_archcpu(env);
41d6ae8ec6SLucas Mateus Castro (alqotel)     qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
42d6ae8ec6SLucas Mateus Castro (alqotel)     assert(!cpu->env.has_hv_mode || !cpu->vhyp);
43d6ae8ec6SLucas Mateus Castro (alqotel) #if defined(TARGET_PPC64)
44d6ae8ec6SLucas Mateus Castro (alqotel)     if (mmu_is_64bit(env->mmu_model)) {
45d6ae8ec6SLucas Mateus Castro (alqotel)         target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE;
46d6ae8ec6SLucas Mateus Castro (alqotel)         target_ulong htabsize = value & SDR_64_HTABSIZE;
47d6ae8ec6SLucas Mateus Castro (alqotel) 
48d6ae8ec6SLucas Mateus Castro (alqotel)         if (value & ~sdr_mask) {
49d6ae8ec6SLucas Mateus Castro (alqotel)             qemu_log_mask(LOG_GUEST_ERROR, "Invalid bits 0x"TARGET_FMT_lx
50d6ae8ec6SLucas Mateus Castro (alqotel)                      " set in SDR1", value & ~sdr_mask);
51d6ae8ec6SLucas Mateus Castro (alqotel)             value &= sdr_mask;
52d6ae8ec6SLucas Mateus Castro (alqotel)         }
53d6ae8ec6SLucas Mateus Castro (alqotel)         if (htabsize > 28) {
54d6ae8ec6SLucas Mateus Castro (alqotel)             qemu_log_mask(LOG_GUEST_ERROR, "Invalid HTABSIZE 0x" TARGET_FMT_lx
55d6ae8ec6SLucas Mateus Castro (alqotel)                      " stored in SDR1", htabsize);
56d6ae8ec6SLucas Mateus Castro (alqotel)             return;
57d6ae8ec6SLucas Mateus Castro (alqotel)         }
58d6ae8ec6SLucas Mateus Castro (alqotel)     }
59d6ae8ec6SLucas Mateus Castro (alqotel) #endif /* defined(TARGET_PPC64) */
60d6ae8ec6SLucas Mateus Castro (alqotel)     /* FIXME: Should check for valid HTABMASK values in 32-bit case */
61d6ae8ec6SLucas Mateus Castro (alqotel)     env->spr[SPR_SDR1] = value;
62d6ae8ec6SLucas Mateus Castro (alqotel) }
63d6ae8ec6SLucas Mateus Castro (alqotel) 
645118ebe8SLucas Mateus Castro (alqotel) /*****************************************************************************/
655118ebe8SLucas Mateus Castro (alqotel) /* PowerPC MMU emulation */
665118ebe8SLucas Mateus Castro (alqotel) 
675118ebe8SLucas Mateus Castro (alqotel) static int pp_check(int key, int pp, int nx)
685118ebe8SLucas Mateus Castro (alqotel) {
695118ebe8SLucas Mateus Castro (alqotel)     int access;
705118ebe8SLucas Mateus Castro (alqotel) 
715118ebe8SLucas Mateus Castro (alqotel)     /* Compute access rights */
725118ebe8SLucas Mateus Castro (alqotel)     access = 0;
735118ebe8SLucas Mateus Castro (alqotel)     if (key == 0) {
745118ebe8SLucas Mateus Castro (alqotel)         switch (pp) {
755118ebe8SLucas Mateus Castro (alqotel)         case 0x0:
765118ebe8SLucas Mateus Castro (alqotel)         case 0x1:
775118ebe8SLucas Mateus Castro (alqotel)         case 0x2:
785118ebe8SLucas Mateus Castro (alqotel)             access |= PAGE_WRITE;
795118ebe8SLucas Mateus Castro (alqotel)             /* fall through */
805118ebe8SLucas Mateus Castro (alqotel)         case 0x3:
815118ebe8SLucas Mateus Castro (alqotel)             access |= PAGE_READ;
825118ebe8SLucas Mateus Castro (alqotel)             break;
835118ebe8SLucas Mateus Castro (alqotel)         }
845118ebe8SLucas Mateus Castro (alqotel)     } else {
855118ebe8SLucas Mateus Castro (alqotel)         switch (pp) {
865118ebe8SLucas Mateus Castro (alqotel)         case 0x0:
875118ebe8SLucas Mateus Castro (alqotel)             access = 0;
885118ebe8SLucas Mateus Castro (alqotel)             break;
895118ebe8SLucas Mateus Castro (alqotel)         case 0x1:
905118ebe8SLucas Mateus Castro (alqotel)         case 0x3:
915118ebe8SLucas Mateus Castro (alqotel)             access = PAGE_READ;
925118ebe8SLucas Mateus Castro (alqotel)             break;
935118ebe8SLucas Mateus Castro (alqotel)         case 0x2:
945118ebe8SLucas Mateus Castro (alqotel)             access = PAGE_READ | PAGE_WRITE;
955118ebe8SLucas Mateus Castro (alqotel)             break;
965118ebe8SLucas Mateus Castro (alqotel)         }
975118ebe8SLucas Mateus Castro (alqotel)     }
985118ebe8SLucas Mateus Castro (alqotel)     if (nx == 0) {
995118ebe8SLucas Mateus Castro (alqotel)         access |= PAGE_EXEC;
1005118ebe8SLucas Mateus Castro (alqotel)     }
1015118ebe8SLucas Mateus Castro (alqotel) 
1025118ebe8SLucas Mateus Castro (alqotel)     return access;
1035118ebe8SLucas Mateus Castro (alqotel) }
1045118ebe8SLucas Mateus Castro (alqotel) 
1055118ebe8SLucas Mateus Castro (alqotel) static int check_prot(int prot, MMUAccessType access_type)
1065118ebe8SLucas Mateus Castro (alqotel) {
1075118ebe8SLucas Mateus Castro (alqotel)     return prot & prot_for_access_type(access_type) ? 0 : -2;
1085118ebe8SLucas Mateus Castro (alqotel) }
1095118ebe8SLucas Mateus Castro (alqotel) 
1105118ebe8SLucas Mateus Castro (alqotel) int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
1115118ebe8SLucas Mateus Castro (alqotel)                                     int way, int is_code)
1125118ebe8SLucas Mateus Castro (alqotel) {
1135118ebe8SLucas Mateus Castro (alqotel)     int nr;
1145118ebe8SLucas Mateus Castro (alqotel) 
1155118ebe8SLucas Mateus Castro (alqotel)     /* Select TLB num in a way from address */
1165118ebe8SLucas Mateus Castro (alqotel)     nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
1175118ebe8SLucas Mateus Castro (alqotel)     /* Select TLB way */
1185118ebe8SLucas Mateus Castro (alqotel)     nr += env->tlb_per_way * way;
1195118ebe8SLucas Mateus Castro (alqotel)     /* 6xx have separate TLBs for instructions and data */
1205118ebe8SLucas Mateus Castro (alqotel)     if (is_code && env->id_tlbs == 1) {
1215118ebe8SLucas Mateus Castro (alqotel)         nr += env->nb_tlb;
1225118ebe8SLucas Mateus Castro (alqotel)     }
1235118ebe8SLucas Mateus Castro (alqotel) 
1245118ebe8SLucas Mateus Castro (alqotel)     return nr;
1255118ebe8SLucas Mateus Castro (alqotel) }
1265118ebe8SLucas Mateus Castro (alqotel) 
1275118ebe8SLucas Mateus Castro (alqotel) static int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
1285118ebe8SLucas Mateus Castro (alqotel)                                 target_ulong pte1, int h,
1295118ebe8SLucas Mateus Castro (alqotel)                                 MMUAccessType access_type)
1305118ebe8SLucas Mateus Castro (alqotel) {
1315118ebe8SLucas Mateus Castro (alqotel)     target_ulong ptem, mmask;
1325118ebe8SLucas Mateus Castro (alqotel)     int access, ret, pteh, ptev, pp;
1335118ebe8SLucas Mateus Castro (alqotel) 
1345118ebe8SLucas Mateus Castro (alqotel)     ret = -1;
1355118ebe8SLucas Mateus Castro (alqotel)     /* Check validity and table match */
1365118ebe8SLucas Mateus Castro (alqotel)     ptev = pte_is_valid(pte0);
1375118ebe8SLucas Mateus Castro (alqotel)     pteh = (pte0 >> 6) & 1;
1385118ebe8SLucas Mateus Castro (alqotel)     if (ptev && h == pteh) {
1395118ebe8SLucas Mateus Castro (alqotel)         /* Check vsid & api */
1405118ebe8SLucas Mateus Castro (alqotel)         ptem = pte0 & PTE_PTEM_MASK;
1415118ebe8SLucas Mateus Castro (alqotel)         mmask = PTE_CHECK_MASK;
1425118ebe8SLucas Mateus Castro (alqotel)         pp = pte1 & 0x00000003;
1435118ebe8SLucas Mateus Castro (alqotel)         if (ptem == ctx->ptem) {
1445118ebe8SLucas Mateus Castro (alqotel)             if (ctx->raddr != (hwaddr)-1ULL) {
1455118ebe8SLucas Mateus Castro (alqotel)                 /* all matches should have equal RPN, WIMG & PP */
1465118ebe8SLucas Mateus Castro (alqotel)                 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
1475118ebe8SLucas Mateus Castro (alqotel)                     qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
1485118ebe8SLucas Mateus Castro (alqotel)                     return -3;
1495118ebe8SLucas Mateus Castro (alqotel)                 }
1505118ebe8SLucas Mateus Castro (alqotel)             }
1515118ebe8SLucas Mateus Castro (alqotel)             /* Compute access rights */
1525118ebe8SLucas Mateus Castro (alqotel)             access = pp_check(ctx->key, pp, ctx->nx);
1535118ebe8SLucas Mateus Castro (alqotel)             /* Keep the matching PTE information */
1545118ebe8SLucas Mateus Castro (alqotel)             ctx->raddr = pte1;
1555118ebe8SLucas Mateus Castro (alqotel)             ctx->prot = access;
1565118ebe8SLucas Mateus Castro (alqotel)             ret = check_prot(ctx->prot, access_type);
1575118ebe8SLucas Mateus Castro (alqotel)             if (ret == 0) {
1585118ebe8SLucas Mateus Castro (alqotel)                 /* Access granted */
1595118ebe8SLucas Mateus Castro (alqotel)                 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
1605118ebe8SLucas Mateus Castro (alqotel)             } else {
1615118ebe8SLucas Mateus Castro (alqotel)                 /* Access right violation */
1625118ebe8SLucas Mateus Castro (alqotel)                 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
1635118ebe8SLucas Mateus Castro (alqotel)             }
1645118ebe8SLucas Mateus Castro (alqotel)         }
1655118ebe8SLucas Mateus Castro (alqotel)     }
1665118ebe8SLucas Mateus Castro (alqotel) 
1675118ebe8SLucas Mateus Castro (alqotel)     return ret;
1685118ebe8SLucas Mateus Castro (alqotel) }
1695118ebe8SLucas Mateus Castro (alqotel) 
1705118ebe8SLucas Mateus Castro (alqotel) static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
1715118ebe8SLucas Mateus Castro (alqotel)                             int ret, MMUAccessType access_type)
1725118ebe8SLucas Mateus Castro (alqotel) {
1735118ebe8SLucas Mateus Castro (alqotel)     int store = 0;
1745118ebe8SLucas Mateus Castro (alqotel) 
1755118ebe8SLucas Mateus Castro (alqotel)     /* Update page flags */
1765118ebe8SLucas Mateus Castro (alqotel)     if (!(*pte1p & 0x00000100)) {
1775118ebe8SLucas Mateus Castro (alqotel)         /* Update accessed flag */
1785118ebe8SLucas Mateus Castro (alqotel)         *pte1p |= 0x00000100;
1795118ebe8SLucas Mateus Castro (alqotel)         store = 1;
1805118ebe8SLucas Mateus Castro (alqotel)     }
1815118ebe8SLucas Mateus Castro (alqotel)     if (!(*pte1p & 0x00000080)) {
1825118ebe8SLucas Mateus Castro (alqotel)         if (access_type == MMU_DATA_STORE && ret == 0) {
1835118ebe8SLucas Mateus Castro (alqotel)             /* Update changed flag */
1845118ebe8SLucas Mateus Castro (alqotel)             *pte1p |= 0x00000080;
1855118ebe8SLucas Mateus Castro (alqotel)             store = 1;
1865118ebe8SLucas Mateus Castro (alqotel)         } else {
1875118ebe8SLucas Mateus Castro (alqotel)             /* Force page fault for first write access */
1885118ebe8SLucas Mateus Castro (alqotel)             ctx->prot &= ~PAGE_WRITE;
1895118ebe8SLucas Mateus Castro (alqotel)         }
1905118ebe8SLucas Mateus Castro (alqotel)     }
1915118ebe8SLucas Mateus Castro (alqotel) 
1925118ebe8SLucas Mateus Castro (alqotel)     return store;
1935118ebe8SLucas Mateus Castro (alqotel) }
1945118ebe8SLucas Mateus Castro (alqotel) 
1955118ebe8SLucas Mateus Castro (alqotel) /* Software driven TLB helpers */
1965118ebe8SLucas Mateus Castro (alqotel) 
1975118ebe8SLucas Mateus Castro (alqotel) static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
1985118ebe8SLucas Mateus Castro (alqotel)                             target_ulong eaddr, MMUAccessType access_type)
1995118ebe8SLucas Mateus Castro (alqotel) {
2005118ebe8SLucas Mateus Castro (alqotel)     ppc6xx_tlb_t *tlb;
2015118ebe8SLucas Mateus Castro (alqotel)     int nr, best, way;
2025118ebe8SLucas Mateus Castro (alqotel)     int ret;
2035118ebe8SLucas Mateus Castro (alqotel) 
2045118ebe8SLucas Mateus Castro (alqotel)     best = -1;
2055118ebe8SLucas Mateus Castro (alqotel)     ret = -1; /* No TLB found */
2065118ebe8SLucas Mateus Castro (alqotel)     for (way = 0; way < env->nb_ways; way++) {
2075118ebe8SLucas Mateus Castro (alqotel)         nr = ppc6xx_tlb_getnum(env, eaddr, way, access_type == MMU_INST_FETCH);
2085118ebe8SLucas Mateus Castro (alqotel)         tlb = &env->tlb.tlb6[nr];
2095118ebe8SLucas Mateus Castro (alqotel)         /* This test "emulates" the PTE index match for hardware TLBs */
2105118ebe8SLucas Mateus Castro (alqotel)         if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
21156964585SCédric Le Goater             qemu_log_mask(CPU_LOG_MMU, "TLB %d/%d %s [" TARGET_FMT_lx
21256964585SCédric Le Goater                           " " TARGET_FMT_lx "] <> " TARGET_FMT_lx "\n",
21356964585SCédric Le Goater                           nr, env->nb_tlb,
2145118ebe8SLucas Mateus Castro (alqotel)                           pte_is_valid(tlb->pte0) ? "valid" : "inval",
2155118ebe8SLucas Mateus Castro (alqotel)                           tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
2165118ebe8SLucas Mateus Castro (alqotel)             continue;
2175118ebe8SLucas Mateus Castro (alqotel)         }
21856964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "TLB %d/%d %s " TARGET_FMT_lx " <> "
21956964585SCédric Le Goater                       TARGET_FMT_lx " " TARGET_FMT_lx " %c %c\n",
22056964585SCédric Le Goater                       nr, env->nb_tlb,
2215118ebe8SLucas Mateus Castro (alqotel)                       pte_is_valid(tlb->pte0) ? "valid" : "inval",
2225118ebe8SLucas Mateus Castro (alqotel)                       tlb->EPN, eaddr, tlb->pte1,
2235118ebe8SLucas Mateus Castro (alqotel)                       access_type == MMU_DATA_STORE ? 'S' : 'L',
2245118ebe8SLucas Mateus Castro (alqotel)                       access_type == MMU_INST_FETCH ? 'I' : 'D');
2255118ebe8SLucas Mateus Castro (alqotel)         switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1,
2265118ebe8SLucas Mateus Castro (alqotel)                                      0, access_type)) {
2275118ebe8SLucas Mateus Castro (alqotel)         case -3:
2285118ebe8SLucas Mateus Castro (alqotel)             /* TLB inconsistency */
2295118ebe8SLucas Mateus Castro (alqotel)             return -1;
2305118ebe8SLucas Mateus Castro (alqotel)         case -2:
2315118ebe8SLucas Mateus Castro (alqotel)             /* Access violation */
2325118ebe8SLucas Mateus Castro (alqotel)             ret = -2;
2335118ebe8SLucas Mateus Castro (alqotel)             best = nr;
2345118ebe8SLucas Mateus Castro (alqotel)             break;
2355118ebe8SLucas Mateus Castro (alqotel)         case -1:
2365118ebe8SLucas Mateus Castro (alqotel)         default:
2375118ebe8SLucas Mateus Castro (alqotel)             /* No match */
2385118ebe8SLucas Mateus Castro (alqotel)             break;
2395118ebe8SLucas Mateus Castro (alqotel)         case 0:
2405118ebe8SLucas Mateus Castro (alqotel)             /* access granted */
2415118ebe8SLucas Mateus Castro (alqotel)             /*
2425118ebe8SLucas Mateus Castro (alqotel)              * XXX: we should go on looping to check all TLBs
2435118ebe8SLucas Mateus Castro (alqotel)              *      consistency but we can speed-up the whole thing as
2445118ebe8SLucas Mateus Castro (alqotel)              *      the result would be undefined if TLBs are not
2455118ebe8SLucas Mateus Castro (alqotel)              *      consistent.
2465118ebe8SLucas Mateus Castro (alqotel)              */
2475118ebe8SLucas Mateus Castro (alqotel)             ret = 0;
2485118ebe8SLucas Mateus Castro (alqotel)             best = nr;
2495118ebe8SLucas Mateus Castro (alqotel)             goto done;
2505118ebe8SLucas Mateus Castro (alqotel)         }
2515118ebe8SLucas Mateus Castro (alqotel)     }
2525118ebe8SLucas Mateus Castro (alqotel)     if (best != -1) {
2535118ebe8SLucas Mateus Castro (alqotel)     done:
254883f2c59SPhilippe Mathieu-Daudé         qemu_log_mask(CPU_LOG_MMU, "found TLB at addr " HWADDR_FMT_plx
25556964585SCédric Le Goater                       " prot=%01x ret=%d\n",
2565118ebe8SLucas Mateus Castro (alqotel)                       ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
2575118ebe8SLucas Mateus Castro (alqotel)         /* Update page flags */
2585118ebe8SLucas Mateus Castro (alqotel)         pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, access_type);
2595118ebe8SLucas Mateus Castro (alqotel)     }
2605118ebe8SLucas Mateus Castro (alqotel) 
2615118ebe8SLucas Mateus Castro (alqotel)     return ret;
2625118ebe8SLucas Mateus Castro (alqotel) }
2635118ebe8SLucas Mateus Castro (alqotel) 
2645118ebe8SLucas Mateus Castro (alqotel) /* Perform BAT hit & translation */
2655118ebe8SLucas Mateus Castro (alqotel) static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
2665118ebe8SLucas Mateus Castro (alqotel)                                  int *validp, int *protp, target_ulong *BATu,
2675118ebe8SLucas Mateus Castro (alqotel)                                  target_ulong *BATl)
2685118ebe8SLucas Mateus Castro (alqotel) {
2695118ebe8SLucas Mateus Castro (alqotel)     target_ulong bl;
2705118ebe8SLucas Mateus Castro (alqotel)     int pp, valid, prot;
2715118ebe8SLucas Mateus Castro (alqotel) 
2725118ebe8SLucas Mateus Castro (alqotel)     bl = (*BATu & 0x00001FFC) << 15;
2735118ebe8SLucas Mateus Castro (alqotel)     valid = 0;
2745118ebe8SLucas Mateus Castro (alqotel)     prot = 0;
275d41ccf6eSVíctor Colombo     if ((!FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000002)) ||
276d41ccf6eSVíctor Colombo         (FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000001))) {
2775118ebe8SLucas Mateus Castro (alqotel)         valid = 1;
2785118ebe8SLucas Mateus Castro (alqotel)         pp = *BATl & 0x00000003;
2795118ebe8SLucas Mateus Castro (alqotel)         if (pp != 0) {
2805118ebe8SLucas Mateus Castro (alqotel)             prot = PAGE_READ | PAGE_EXEC;
2815118ebe8SLucas Mateus Castro (alqotel)             if (pp == 0x2) {
2825118ebe8SLucas Mateus Castro (alqotel)                 prot |= PAGE_WRITE;
2835118ebe8SLucas Mateus Castro (alqotel)             }
2845118ebe8SLucas Mateus Castro (alqotel)         }
2855118ebe8SLucas Mateus Castro (alqotel)     }
2865118ebe8SLucas Mateus Castro (alqotel)     *blp = bl;
2875118ebe8SLucas Mateus Castro (alqotel)     *validp = valid;
2885118ebe8SLucas Mateus Castro (alqotel)     *protp = prot;
2895118ebe8SLucas Mateus Castro (alqotel) }
2905118ebe8SLucas Mateus Castro (alqotel) 
2915118ebe8SLucas Mateus Castro (alqotel) static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
2925118ebe8SLucas Mateus Castro (alqotel)                            target_ulong virtual, MMUAccessType access_type)
2935118ebe8SLucas Mateus Castro (alqotel) {
2945118ebe8SLucas Mateus Castro (alqotel)     target_ulong *BATlt, *BATut, *BATu, *BATl;
2955118ebe8SLucas Mateus Castro (alqotel)     target_ulong BEPIl, BEPIu, bl;
2965118ebe8SLucas Mateus Castro (alqotel)     int i, valid, prot;
2975118ebe8SLucas Mateus Castro (alqotel)     int ret = -1;
2985118ebe8SLucas Mateus Castro (alqotel)     bool ifetch = access_type == MMU_INST_FETCH;
2995118ebe8SLucas Mateus Castro (alqotel) 
30056964585SCédric Le Goater      qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
3015118ebe8SLucas Mateus Castro (alqotel)              ifetch ? 'I' : 'D', virtual);
3025118ebe8SLucas Mateus Castro (alqotel)     if (ifetch) {
3035118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->IBAT[1];
3045118ebe8SLucas Mateus Castro (alqotel)         BATut = env->IBAT[0];
3055118ebe8SLucas Mateus Castro (alqotel)     } else {
3065118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->DBAT[1];
3075118ebe8SLucas Mateus Castro (alqotel)         BATut = env->DBAT[0];
3085118ebe8SLucas Mateus Castro (alqotel)     }
3095118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_BATs; i++) {
3105118ebe8SLucas Mateus Castro (alqotel)         BATu = &BATut[i];
3115118ebe8SLucas Mateus Castro (alqotel)         BATl = &BATlt[i];
3125118ebe8SLucas Mateus Castro (alqotel)         BEPIu = *BATu & 0xF0000000;
3135118ebe8SLucas Mateus Castro (alqotel)         BEPIl = *BATu & 0x0FFE0000;
3145118ebe8SLucas Mateus Castro (alqotel)         bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
31556964585SCédric Le Goater          qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx " BATu "
31656964585SCédric Le Goater                        TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n", __func__,
3175118ebe8SLucas Mateus Castro (alqotel)                        ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl);
3185118ebe8SLucas Mateus Castro (alqotel)         if ((virtual & 0xF0000000) == BEPIu &&
3195118ebe8SLucas Mateus Castro (alqotel)             ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
3205118ebe8SLucas Mateus Castro (alqotel)             /* BAT matches */
3215118ebe8SLucas Mateus Castro (alqotel)             if (valid != 0) {
3225118ebe8SLucas Mateus Castro (alqotel)                 /* Get physical address */
3235118ebe8SLucas Mateus Castro (alqotel)                 ctx->raddr = (*BATl & 0xF0000000) |
3245118ebe8SLucas Mateus Castro (alqotel)                     ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
3255118ebe8SLucas Mateus Castro (alqotel)                     (virtual & 0x0001F000);
3265118ebe8SLucas Mateus Castro (alqotel)                 /* Compute access rights */
3275118ebe8SLucas Mateus Castro (alqotel)                 ctx->prot = prot;
3285118ebe8SLucas Mateus Castro (alqotel)                 ret = check_prot(ctx->prot, access_type);
3295118ebe8SLucas Mateus Castro (alqotel)                 if (ret == 0) {
330883f2c59SPhilippe Mathieu-Daudé                     qemu_log_mask(CPU_LOG_MMU, "BAT %d match: r " HWADDR_FMT_plx
33156964585SCédric Le Goater                                   " prot=%c%c\n", i, ctx->raddr,
33256964585SCédric Le Goater                                   ctx->prot & PAGE_READ ? 'R' : '-',
3335118ebe8SLucas Mateus Castro (alqotel)                                   ctx->prot & PAGE_WRITE ? 'W' : '-');
3345118ebe8SLucas Mateus Castro (alqotel)                 }
3355118ebe8SLucas Mateus Castro (alqotel)                 break;
3365118ebe8SLucas Mateus Castro (alqotel)             }
3375118ebe8SLucas Mateus Castro (alqotel)         }
3385118ebe8SLucas Mateus Castro (alqotel)     }
3395118ebe8SLucas Mateus Castro (alqotel)     if (ret < 0) {
3405118ebe8SLucas Mateus Castro (alqotel)         if (qemu_log_enabled()) {
34156964585SCédric Le Goater             qemu_log_mask(CPU_LOG_MMU, "no BAT match for "
34256964585SCédric Le Goater                           TARGET_FMT_lx ":\n", virtual);
3435118ebe8SLucas Mateus Castro (alqotel)             for (i = 0; i < 4; i++) {
3445118ebe8SLucas Mateus Castro (alqotel)                 BATu = &BATut[i];
3455118ebe8SLucas Mateus Castro (alqotel)                 BATl = &BATlt[i];
3465118ebe8SLucas Mateus Castro (alqotel)                 BEPIu = *BATu & 0xF0000000;
3475118ebe8SLucas Mateus Castro (alqotel)                 BEPIl = *BATu & 0x0FFE0000;
3485118ebe8SLucas Mateus Castro (alqotel)                 bl = (*BATu & 0x00001FFC) << 15;
34956964585SCédric Le Goater                  qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v "
35056964585SCédric Le Goater                                TARGET_FMT_lx " BATu " TARGET_FMT_lx
3515118ebe8SLucas Mateus Castro (alqotel)                                " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
3525118ebe8SLucas Mateus Castro (alqotel)                                TARGET_FMT_lx " " TARGET_FMT_lx "\n",
3535118ebe8SLucas Mateus Castro (alqotel)                                __func__, ifetch ? 'I' : 'D', i, virtual,
3545118ebe8SLucas Mateus Castro (alqotel)                                *BATu, *BATl, BEPIu, BEPIl, bl);
3555118ebe8SLucas Mateus Castro (alqotel)             }
3565118ebe8SLucas Mateus Castro (alqotel)         }
3575118ebe8SLucas Mateus Castro (alqotel)     }
3585118ebe8SLucas Mateus Castro (alqotel)     /* No hit */
3595118ebe8SLucas Mateus Castro (alqotel)     return ret;
3605118ebe8SLucas Mateus Castro (alqotel) }
3615118ebe8SLucas Mateus Castro (alqotel) 
3625118ebe8SLucas Mateus Castro (alqotel) /* Perform segment based translation */
3635118ebe8SLucas Mateus Castro (alqotel) static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
3645118ebe8SLucas Mateus Castro (alqotel)                                target_ulong eaddr, MMUAccessType access_type,
3655118ebe8SLucas Mateus Castro (alqotel)                                int type)
3665118ebe8SLucas Mateus Castro (alqotel) {
3675118ebe8SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = env_archcpu(env);
3685118ebe8SLucas Mateus Castro (alqotel)     hwaddr hash;
3695118ebe8SLucas Mateus Castro (alqotel)     target_ulong vsid;
370d41ccf6eSVíctor Colombo     int ds, target_page_bits;
371d41ccf6eSVíctor Colombo     bool pr;
3725118ebe8SLucas Mateus Castro (alqotel)     int ret;
3735118ebe8SLucas Mateus Castro (alqotel)     target_ulong sr, pgidx;
3745118ebe8SLucas Mateus Castro (alqotel) 
375d41ccf6eSVíctor Colombo     pr = FIELD_EX64(env->msr, MSR, PR);
3765118ebe8SLucas Mateus Castro (alqotel)     ctx->eaddr = eaddr;
3775118ebe8SLucas Mateus Castro (alqotel) 
3785118ebe8SLucas Mateus Castro (alqotel)     sr = env->sr[eaddr >> 28];
379d41ccf6eSVíctor Colombo     ctx->key = (((sr & 0x20000000) && pr) ||
380d41ccf6eSVíctor Colombo                 ((sr & 0x40000000) && !pr)) ? 1 : 0;
3815118ebe8SLucas Mateus Castro (alqotel)     ds = sr & 0x80000000 ? 1 : 0;
3825118ebe8SLucas Mateus Castro (alqotel)     ctx->nx = sr & 0x10000000 ? 1 : 0;
3835118ebe8SLucas Mateus Castro (alqotel)     vsid = sr & 0x00FFFFFF;
3845118ebe8SLucas Mateus Castro (alqotel)     target_page_bits = TARGET_PAGE_BITS;
3855118ebe8SLucas Mateus Castro (alqotel)     qemu_log_mask(CPU_LOG_MMU,
3865118ebe8SLucas Mateus Castro (alqotel)                   "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
3875118ebe8SLucas Mateus Castro (alqotel)                   " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
3885118ebe8SLucas Mateus Castro (alqotel)                   " ir=%d dr=%d pr=%d %d t=%d\n",
389d41ccf6eSVíctor Colombo                   eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr,
390e4eea6efSVíctor Colombo                   (int)FIELD_EX64(env->msr, MSR, IR),
391e4eea6efSVíctor Colombo                   (int)FIELD_EX64(env->msr, MSR, DR), pr ? 1 : 0,
39256964585SCédric Le Goater                   access_type == MMU_DATA_STORE, type);
3935118ebe8SLucas Mateus Castro (alqotel)     pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
3945118ebe8SLucas Mateus Castro (alqotel)     hash = vsid ^ pgidx;
3955118ebe8SLucas Mateus Castro (alqotel)     ctx->ptem = (vsid << 7) | (pgidx >> 10);
3965118ebe8SLucas Mateus Castro (alqotel) 
3975118ebe8SLucas Mateus Castro (alqotel)     qemu_log_mask(CPU_LOG_MMU,
3985118ebe8SLucas Mateus Castro (alqotel)             "pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
3995118ebe8SLucas Mateus Castro (alqotel)             ctx->key, ds, ctx->nx, vsid);
4005118ebe8SLucas Mateus Castro (alqotel)     ret = -1;
4015118ebe8SLucas Mateus Castro (alqotel)     if (!ds) {
4025118ebe8SLucas Mateus Castro (alqotel)         /* Check if instruction fetch is allowed, if needed */
4035118ebe8SLucas Mateus Castro (alqotel)         if (type != ACCESS_CODE || ctx->nx == 0) {
4045118ebe8SLucas Mateus Castro (alqotel)             /* Page address translation */
405883f2c59SPhilippe Mathieu-Daudé             qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx
406883f2c59SPhilippe Mathieu-Daudé                     " htab_mask " HWADDR_FMT_plx
407883f2c59SPhilippe Mathieu-Daudé                     " hash " HWADDR_FMT_plx "\n",
4085118ebe8SLucas Mateus Castro (alqotel)                     ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
4095118ebe8SLucas Mateus Castro (alqotel)             ctx->hash[0] = hash;
4105118ebe8SLucas Mateus Castro (alqotel)             ctx->hash[1] = ~hash;
4115118ebe8SLucas Mateus Castro (alqotel) 
4125118ebe8SLucas Mateus Castro (alqotel)             /* Initialize real address with an invalid value */
4135118ebe8SLucas Mateus Castro (alqotel)             ctx->raddr = (hwaddr)-1ULL;
4145118ebe8SLucas Mateus Castro (alqotel)             /* Software TLB search */
4155118ebe8SLucas Mateus Castro (alqotel)             ret = ppc6xx_tlb_check(env, ctx, eaddr, access_type);
4165118ebe8SLucas Mateus Castro (alqotel) #if defined(DUMP_PAGE_TABLES)
4175118ebe8SLucas Mateus Castro (alqotel)             if (qemu_loglevel_mask(CPU_LOG_MMU)) {
4185118ebe8SLucas Mateus Castro (alqotel)                 CPUState *cs = env_cpu(env);
4195118ebe8SLucas Mateus Castro (alqotel)                 hwaddr curaddr;
4205118ebe8SLucas Mateus Castro (alqotel)                 uint32_t a0, a1, a2, a3;
4215118ebe8SLucas Mateus Castro (alqotel) 
422883f2c59SPhilippe Mathieu-Daudé                 qemu_log("Page table: " HWADDR_FMT_plx " len " HWADDR_FMT_plx
4235118ebe8SLucas Mateus Castro (alqotel)                          "\n", ppc_hash32_hpt_base(cpu),
4245118ebe8SLucas Mateus Castro (alqotel)                          ppc_hash32_hpt_mask(cpu) + 0x80);
4255118ebe8SLucas Mateus Castro (alqotel)                 for (curaddr = ppc_hash32_hpt_base(cpu);
4265118ebe8SLucas Mateus Castro (alqotel)                      curaddr < (ppc_hash32_hpt_base(cpu)
4275118ebe8SLucas Mateus Castro (alqotel)                                 + ppc_hash32_hpt_mask(cpu) + 0x80);
4285118ebe8SLucas Mateus Castro (alqotel)                      curaddr += 16) {
4295118ebe8SLucas Mateus Castro (alqotel)                     a0 = ldl_phys(cs->as, curaddr);
4305118ebe8SLucas Mateus Castro (alqotel)                     a1 = ldl_phys(cs->as, curaddr + 4);
4315118ebe8SLucas Mateus Castro (alqotel)                     a2 = ldl_phys(cs->as, curaddr + 8);
4325118ebe8SLucas Mateus Castro (alqotel)                     a3 = ldl_phys(cs->as, curaddr + 12);
4335118ebe8SLucas Mateus Castro (alqotel)                     if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
434883f2c59SPhilippe Mathieu-Daudé                         qemu_log(HWADDR_FMT_plx ": %08x %08x %08x %08x\n",
4355118ebe8SLucas Mateus Castro (alqotel)                                  curaddr, a0, a1, a2, a3);
4365118ebe8SLucas Mateus Castro (alqotel)                     }
4375118ebe8SLucas Mateus Castro (alqotel)                 }
4385118ebe8SLucas Mateus Castro (alqotel)             }
4395118ebe8SLucas Mateus Castro (alqotel) #endif
4405118ebe8SLucas Mateus Castro (alqotel)         } else {
4415118ebe8SLucas Mateus Castro (alqotel)             qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
4425118ebe8SLucas Mateus Castro (alqotel)             ret = -3;
4435118ebe8SLucas Mateus Castro (alqotel)         }
4445118ebe8SLucas Mateus Castro (alqotel)     } else {
4455118ebe8SLucas Mateus Castro (alqotel)         qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
4465118ebe8SLucas Mateus Castro (alqotel)         /* Direct-store segment : absolutely *BUGGY* for now */
4475118ebe8SLucas Mateus Castro (alqotel) 
4485118ebe8SLucas Mateus Castro (alqotel)         switch (type) {
4495118ebe8SLucas Mateus Castro (alqotel)         case ACCESS_INT:
4505118ebe8SLucas Mateus Castro (alqotel)             /* Integer load/store : only access allowed */
4515118ebe8SLucas Mateus Castro (alqotel)             break;
4525118ebe8SLucas Mateus Castro (alqotel)         case ACCESS_CODE:
4535118ebe8SLucas Mateus Castro (alqotel)             /* No code fetch is allowed in direct-store areas */
4545118ebe8SLucas Mateus Castro (alqotel)             return -4;
4555118ebe8SLucas Mateus Castro (alqotel)         case ACCESS_FLOAT:
4565118ebe8SLucas Mateus Castro (alqotel)             /* Floating point load/store */
4575118ebe8SLucas Mateus Castro (alqotel)             return -4;
4585118ebe8SLucas Mateus Castro (alqotel)         case ACCESS_RES:
4595118ebe8SLucas Mateus Castro (alqotel)             /* lwarx, ldarx or srwcx. */
4605118ebe8SLucas Mateus Castro (alqotel)             return -4;
4615118ebe8SLucas Mateus Castro (alqotel)         case ACCESS_CACHE:
4625118ebe8SLucas Mateus Castro (alqotel)             /*
4635118ebe8SLucas Mateus Castro (alqotel)              * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
4645118ebe8SLucas Mateus Castro (alqotel)              *
4655118ebe8SLucas Mateus Castro (alqotel)              * Should make the instruction do no-op.  As it already do
4665118ebe8SLucas Mateus Castro (alqotel)              * no-op, it's quite easy :-)
4675118ebe8SLucas Mateus Castro (alqotel)              */
4685118ebe8SLucas Mateus Castro (alqotel)             ctx->raddr = eaddr;
4695118ebe8SLucas Mateus Castro (alqotel)             return 0;
4705118ebe8SLucas Mateus Castro (alqotel)         case ACCESS_EXT:
4715118ebe8SLucas Mateus Castro (alqotel)             /* eciwx or ecowx */
4725118ebe8SLucas Mateus Castro (alqotel)             return -4;
4735118ebe8SLucas Mateus Castro (alqotel)         default:
4745118ebe8SLucas Mateus Castro (alqotel)             qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need "
4755118ebe8SLucas Mateus Castro (alqotel)                           "address translation\n");
4765118ebe8SLucas Mateus Castro (alqotel)             return -4;
4775118ebe8SLucas Mateus Castro (alqotel)         }
4785118ebe8SLucas Mateus Castro (alqotel)         if ((access_type == MMU_DATA_STORE || ctx->key != 1) &&
4795118ebe8SLucas Mateus Castro (alqotel)             (access_type == MMU_DATA_LOAD || ctx->key != 0)) {
4805118ebe8SLucas Mateus Castro (alqotel)             ctx->raddr = eaddr;
4815118ebe8SLucas Mateus Castro (alqotel)             ret = 2;
4825118ebe8SLucas Mateus Castro (alqotel)         } else {
4835118ebe8SLucas Mateus Castro (alqotel)             ret = -2;
4845118ebe8SLucas Mateus Castro (alqotel)         }
4855118ebe8SLucas Mateus Castro (alqotel)     }
4865118ebe8SLucas Mateus Castro (alqotel) 
4875118ebe8SLucas Mateus Castro (alqotel)     return ret;
4885118ebe8SLucas Mateus Castro (alqotel) }
4895118ebe8SLucas Mateus Castro (alqotel) 
4905118ebe8SLucas Mateus Castro (alqotel) /* Generic TLB check function for embedded PowerPC implementations */
4912b23daa8SBALATON Zoltan static bool ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
4925118ebe8SLucas Mateus Castro (alqotel)                              hwaddr *raddrp,
49362860c5fSBALATON Zoltan                              target_ulong address, uint32_t pid, int i)
4945118ebe8SLucas Mateus Castro (alqotel) {
4955118ebe8SLucas Mateus Castro (alqotel)     target_ulong mask;
4965118ebe8SLucas Mateus Castro (alqotel) 
4975118ebe8SLucas Mateus Castro (alqotel)     /* Check valid flag */
4985118ebe8SLucas Mateus Castro (alqotel)     if (!(tlb->prot & PAGE_VALID)) {
4992b23daa8SBALATON Zoltan         return false;
5005118ebe8SLucas Mateus Castro (alqotel)     }
5015118ebe8SLucas Mateus Castro (alqotel)     mask = ~(tlb->size - 1);
50256964585SCédric Le Goater     qemu_log_mask(CPU_LOG_MMU, "%s: TLB %d address " TARGET_FMT_lx
50356964585SCédric Le Goater                   " PID %u <=> " TARGET_FMT_lx " " TARGET_FMT_lx " %u %x\n",
50456964585SCédric Le Goater                   __func__, i, address, pid, tlb->EPN,
5055118ebe8SLucas Mateus Castro (alqotel)                   mask, (uint32_t)tlb->PID, tlb->prot);
5065118ebe8SLucas Mateus Castro (alqotel)     /* Check PID */
5075118ebe8SLucas Mateus Castro (alqotel)     if (tlb->PID != 0 && tlb->PID != pid) {
5082b23daa8SBALATON Zoltan         return false;
5095118ebe8SLucas Mateus Castro (alqotel)     }
5105118ebe8SLucas Mateus Castro (alqotel)     /* Check effective address */
5115118ebe8SLucas Mateus Castro (alqotel)     if ((address & mask) != tlb->EPN) {
5122b23daa8SBALATON Zoltan         return false;
5135118ebe8SLucas Mateus Castro (alqotel)     }
5145118ebe8SLucas Mateus Castro (alqotel)     *raddrp = (tlb->RPN & mask) | (address & ~mask);
5152b23daa8SBALATON Zoltan     return true;
5165118ebe8SLucas Mateus Castro (alqotel) }
5175118ebe8SLucas Mateus Castro (alqotel) 
518753441c8SBALATON Zoltan /* Generic TLB search function for PowerPC embedded implementations */
519753441c8SBALATON Zoltan int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid)
520753441c8SBALATON Zoltan {
521753441c8SBALATON Zoltan     ppcemb_tlb_t *tlb;
522753441c8SBALATON Zoltan     hwaddr raddr;
523bb60364cSBALATON Zoltan     int i;
524753441c8SBALATON Zoltan 
525753441c8SBALATON Zoltan     for (i = 0; i < env->nb_tlb; i++) {
526753441c8SBALATON Zoltan         tlb = &env->tlb.tlbe[i];
5272b23daa8SBALATON Zoltan         if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, i)) {
528bb60364cSBALATON Zoltan             return i;
529753441c8SBALATON Zoltan         }
530753441c8SBALATON Zoltan     }
531bb60364cSBALATON Zoltan     return -1;
532753441c8SBALATON Zoltan }
533753441c8SBALATON Zoltan 
5345118ebe8SLucas Mateus Castro (alqotel) static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
5355118ebe8SLucas Mateus Castro (alqotel)                                        target_ulong address,
5365118ebe8SLucas Mateus Castro (alqotel)                                        MMUAccessType access_type)
5375118ebe8SLucas Mateus Castro (alqotel) {
5385118ebe8SLucas Mateus Castro (alqotel)     ppcemb_tlb_t *tlb;
5395118ebe8SLucas Mateus Castro (alqotel)     hwaddr raddr;
5405118ebe8SLucas Mateus Castro (alqotel)     int i, ret, zsel, zpr, pr;
5415118ebe8SLucas Mateus Castro (alqotel) 
5425118ebe8SLucas Mateus Castro (alqotel)     ret = -1;
5435118ebe8SLucas Mateus Castro (alqotel)     raddr = (hwaddr)-1ULL;
544d41ccf6eSVíctor Colombo     pr = FIELD_EX64(env->msr, MSR, PR);
5455118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_tlb; i++) {
5465118ebe8SLucas Mateus Castro (alqotel)         tlb = &env->tlb.tlbe[i];
5472b23daa8SBALATON Zoltan         if (!ppcemb_tlb_check(env, tlb, &raddr, address,
5482b23daa8SBALATON Zoltan                               env->spr[SPR_40x_PID], i)) {
5495118ebe8SLucas Mateus Castro (alqotel)             continue;
5505118ebe8SLucas Mateus Castro (alqotel)         }
5515118ebe8SLucas Mateus Castro (alqotel)         zsel = (tlb->attr >> 4) & 0xF;
5525118ebe8SLucas Mateus Castro (alqotel)         zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
55356964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU,
55456964585SCédric Le Goater                       "%s: TLB %d zsel %d zpr %d ty %d attr %08x\n",
5555118ebe8SLucas Mateus Castro (alqotel)                       __func__, i, zsel, zpr, access_type, tlb->attr);
5565118ebe8SLucas Mateus Castro (alqotel)         /* Check execute enable bit */
5575118ebe8SLucas Mateus Castro (alqotel)         switch (zpr) {
5585118ebe8SLucas Mateus Castro (alqotel)         case 0x2:
5595118ebe8SLucas Mateus Castro (alqotel)             if (pr != 0) {
5605118ebe8SLucas Mateus Castro (alqotel)                 goto check_perms;
5615118ebe8SLucas Mateus Castro (alqotel)             }
5625118ebe8SLucas Mateus Castro (alqotel)             /* fall through */
5635118ebe8SLucas Mateus Castro (alqotel)         case 0x3:
5645118ebe8SLucas Mateus Castro (alqotel)             /* All accesses granted */
5655118ebe8SLucas Mateus Castro (alqotel)             ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
5665118ebe8SLucas Mateus Castro (alqotel)             ret = 0;
5675118ebe8SLucas Mateus Castro (alqotel)             break;
5685118ebe8SLucas Mateus Castro (alqotel)         case 0x0:
5695118ebe8SLucas Mateus Castro (alqotel)             if (pr != 0) {
5705118ebe8SLucas Mateus Castro (alqotel)                 /* Raise Zone protection fault.  */
5715118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_40x_ESR] = 1 << 22;
5725118ebe8SLucas Mateus Castro (alqotel)                 ctx->prot = 0;
5735118ebe8SLucas Mateus Castro (alqotel)                 ret = -2;
5745118ebe8SLucas Mateus Castro (alqotel)                 break;
5755118ebe8SLucas Mateus Castro (alqotel)             }
5765118ebe8SLucas Mateus Castro (alqotel)             /* fall through */
5775118ebe8SLucas Mateus Castro (alqotel)         case 0x1:
5785118ebe8SLucas Mateus Castro (alqotel)         check_perms:
5795118ebe8SLucas Mateus Castro (alqotel)             /* Check from TLB entry */
5805118ebe8SLucas Mateus Castro (alqotel)             ctx->prot = tlb->prot;
5815118ebe8SLucas Mateus Castro (alqotel)             ret = check_prot(ctx->prot, access_type);
5825118ebe8SLucas Mateus Castro (alqotel)             if (ret == -2) {
5835118ebe8SLucas Mateus Castro (alqotel)                 env->spr[SPR_40x_ESR] = 0;
5845118ebe8SLucas Mateus Castro (alqotel)             }
5855118ebe8SLucas Mateus Castro (alqotel)             break;
5865118ebe8SLucas Mateus Castro (alqotel)         }
5875118ebe8SLucas Mateus Castro (alqotel)         if (ret >= 0) {
5885118ebe8SLucas Mateus Castro (alqotel)             ctx->raddr = raddr;
58956964585SCédric Le Goater             qemu_log_mask(CPU_LOG_MMU, "%s: access granted " TARGET_FMT_lx
590883f2c59SPhilippe Mathieu-Daudé                           " => " HWADDR_FMT_plx
5915118ebe8SLucas Mateus Castro (alqotel)                           " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
5925118ebe8SLucas Mateus Castro (alqotel)                           ret);
5935118ebe8SLucas Mateus Castro (alqotel)             return 0;
5945118ebe8SLucas Mateus Castro (alqotel)         }
5955118ebe8SLucas Mateus Castro (alqotel)     }
59656964585SCédric Le Goater      qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx
597883f2c59SPhilippe Mathieu-Daudé                    " => " HWADDR_FMT_plx
5985118ebe8SLucas Mateus Castro (alqotel)                    " %d %d\n", __func__, address, raddr, ctx->prot, ret);
5995118ebe8SLucas Mateus Castro (alqotel) 
6005118ebe8SLucas Mateus Castro (alqotel)     return ret;
6015118ebe8SLucas Mateus Castro (alqotel) }
6025118ebe8SLucas Mateus Castro (alqotel) 
603a5436bc6SBALATON Zoltan static bool mmubooke_check_pid(CPUPPCState *env, ppcemb_tlb_t *tlb,
604a5436bc6SBALATON Zoltan                                hwaddr *raddr, target_ulong addr, int i)
605a5436bc6SBALATON Zoltan {
606a5436bc6SBALATON Zoltan     if (ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID], i)) {
607a5436bc6SBALATON Zoltan         if (!env->nb_pids) {
608a5436bc6SBALATON Zoltan             /* Extend the physical address to 36 bits */
609a5436bc6SBALATON Zoltan             *raddr |= (uint64_t)(tlb->RPN & 0xF) << 32;
610a5436bc6SBALATON Zoltan         }
611a5436bc6SBALATON Zoltan         return true;
612a5436bc6SBALATON Zoltan     } else if (!env->nb_pids) {
613a5436bc6SBALATON Zoltan         return false;
614a5436bc6SBALATON Zoltan     }
615a5436bc6SBALATON Zoltan     if (env->spr[SPR_BOOKE_PID1] &&
616a5436bc6SBALATON Zoltan         ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID1], i)) {
617a5436bc6SBALATON Zoltan         return true;
618a5436bc6SBALATON Zoltan     }
619a5436bc6SBALATON Zoltan     if (env->spr[SPR_BOOKE_PID2] &&
620a5436bc6SBALATON Zoltan         ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID2], i)) {
621a5436bc6SBALATON Zoltan         return true;
622a5436bc6SBALATON Zoltan     }
623a5436bc6SBALATON Zoltan     return false;
624a5436bc6SBALATON Zoltan }
625a5436bc6SBALATON Zoltan 
6265118ebe8SLucas Mateus Castro (alqotel) static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
6275118ebe8SLucas Mateus Castro (alqotel)                               hwaddr *raddr, int *prot, target_ulong address,
6285118ebe8SLucas Mateus Castro (alqotel)                               MMUAccessType access_type, int i)
6295118ebe8SLucas Mateus Castro (alqotel) {
6305118ebe8SLucas Mateus Castro (alqotel)     int prot2;
6315118ebe8SLucas Mateus Castro (alqotel) 
632a5436bc6SBALATON Zoltan     if (!mmubooke_check_pid(env, tlb, raddr, address, i)) {
63356964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: TLB entry not found\n", __func__);
6345118ebe8SLucas Mateus Castro (alqotel)         return -1;
635a5436bc6SBALATON Zoltan     }
6365118ebe8SLucas Mateus Castro (alqotel) 
637d41ccf6eSVíctor Colombo     if (FIELD_EX64(env->msr, MSR, PR)) {
6385118ebe8SLucas Mateus Castro (alqotel)         prot2 = tlb->prot & 0xF;
6395118ebe8SLucas Mateus Castro (alqotel)     } else {
6405118ebe8SLucas Mateus Castro (alqotel)         prot2 = (tlb->prot >> 4) & 0xF;
6415118ebe8SLucas Mateus Castro (alqotel)     }
6425118ebe8SLucas Mateus Castro (alqotel) 
6435118ebe8SLucas Mateus Castro (alqotel)     /* Check the address space */
6444d979c9fSVíctor Colombo     if ((access_type == MMU_INST_FETCH ?
645e4eea6efSVíctor Colombo         FIELD_EX64(env->msr, MSR, IR) :
646e4eea6efSVíctor Colombo         FIELD_EX64(env->msr, MSR, DR)) != (tlb->attr & 1)) {
64756964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
6485118ebe8SLucas Mateus Castro (alqotel)         return -1;
6495118ebe8SLucas Mateus Castro (alqotel)     }
6505118ebe8SLucas Mateus Castro (alqotel) 
6515118ebe8SLucas Mateus Castro (alqotel)     *prot = prot2;
6525118ebe8SLucas Mateus Castro (alqotel)     if (prot2 & prot_for_access_type(access_type)) {
65356964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
6545118ebe8SLucas Mateus Castro (alqotel)         return 0;
6555118ebe8SLucas Mateus Castro (alqotel)     }
6565118ebe8SLucas Mateus Castro (alqotel) 
65756964585SCédric Le Goater     qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, prot2);
6585118ebe8SLucas Mateus Castro (alqotel)     return access_type == MMU_INST_FETCH ? -3 : -2;
6595118ebe8SLucas Mateus Castro (alqotel) }
6605118ebe8SLucas Mateus Castro (alqotel) 
6615118ebe8SLucas Mateus Castro (alqotel) static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
6625118ebe8SLucas Mateus Castro (alqotel)                                          target_ulong address,
6635118ebe8SLucas Mateus Castro (alqotel)                                          MMUAccessType access_type)
6645118ebe8SLucas Mateus Castro (alqotel) {
6655118ebe8SLucas Mateus Castro (alqotel)     ppcemb_tlb_t *tlb;
6665118ebe8SLucas Mateus Castro (alqotel)     hwaddr raddr;
6675118ebe8SLucas Mateus Castro (alqotel)     int i, ret;
6685118ebe8SLucas Mateus Castro (alqotel) 
6695118ebe8SLucas Mateus Castro (alqotel)     ret = -1;
6705118ebe8SLucas Mateus Castro (alqotel)     raddr = (hwaddr)-1ULL;
6715118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_tlb; i++) {
6725118ebe8SLucas Mateus Castro (alqotel)         tlb = &env->tlb.tlbe[i];
6735118ebe8SLucas Mateus Castro (alqotel)         ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address,
6745118ebe8SLucas Mateus Castro (alqotel)                                  access_type, i);
6755118ebe8SLucas Mateus Castro (alqotel)         if (ret != -1) {
6765118ebe8SLucas Mateus Castro (alqotel)             break;
6775118ebe8SLucas Mateus Castro (alqotel)         }
6785118ebe8SLucas Mateus Castro (alqotel)     }
6795118ebe8SLucas Mateus Castro (alqotel) 
6805118ebe8SLucas Mateus Castro (alqotel)     if (ret >= 0) {
6815118ebe8SLucas Mateus Castro (alqotel)         ctx->raddr = raddr;
68256964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: access granted " TARGET_FMT_lx
683883f2c59SPhilippe Mathieu-Daudé                       " => " HWADDR_FMT_plx " %d %d\n", __func__,
68456964585SCédric Le Goater                       address, ctx->raddr, ctx->prot, ret);
6855118ebe8SLucas Mateus Castro (alqotel)     } else {
68656964585SCédric Le Goater          qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx
687883f2c59SPhilippe Mathieu-Daudé                        " => " HWADDR_FMT_plx " %d %d\n", __func__,
68856964585SCédric Le Goater                        address, raddr, ctx->prot, ret);
6895118ebe8SLucas Mateus Castro (alqotel)     }
6905118ebe8SLucas Mateus Castro (alqotel) 
6915118ebe8SLucas Mateus Castro (alqotel)     return ret;
6925118ebe8SLucas Mateus Castro (alqotel) }
6935118ebe8SLucas Mateus Castro (alqotel) 
694a1fa47faSBALATON Zoltan hwaddr booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb)
6955118ebe8SLucas Mateus Castro (alqotel) {
6965118ebe8SLucas Mateus Castro (alqotel)     int tlbm_size;
6975118ebe8SLucas Mateus Castro (alqotel) 
6985118ebe8SLucas Mateus Castro (alqotel)     tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
6995118ebe8SLucas Mateus Castro (alqotel) 
7005118ebe8SLucas Mateus Castro (alqotel)     return 1024ULL << tlbm_size;
7015118ebe8SLucas Mateus Castro (alqotel) }
7025118ebe8SLucas Mateus Castro (alqotel) 
7035118ebe8SLucas Mateus Castro (alqotel) /* TLB check function for MAS based SoftTLBs */
704a1fa47faSBALATON Zoltan int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddrp,
705a1fa47faSBALATON Zoltan                      target_ulong address, uint32_t pid)
7065118ebe8SLucas Mateus Castro (alqotel) {
7075118ebe8SLucas Mateus Castro (alqotel)     hwaddr mask;
7085118ebe8SLucas Mateus Castro (alqotel)     uint32_t tlb_pid;
7095118ebe8SLucas Mateus Castro (alqotel) 
710cda23360SVíctor Colombo     if (!FIELD_EX64(env->msr, MSR, CM)) {
7115118ebe8SLucas Mateus Castro (alqotel)         /* In 32bit mode we can only address 32bit EAs */
7125118ebe8SLucas Mateus Castro (alqotel)         address = (uint32_t)address;
7135118ebe8SLucas Mateus Castro (alqotel)     }
7145118ebe8SLucas Mateus Castro (alqotel) 
7155118ebe8SLucas Mateus Castro (alqotel)     /* Check valid flag */
7165118ebe8SLucas Mateus Castro (alqotel)     if (!(tlb->mas1 & MAS1_VALID)) {
7175118ebe8SLucas Mateus Castro (alqotel)         return -1;
7185118ebe8SLucas Mateus Castro (alqotel)     }
7195118ebe8SLucas Mateus Castro (alqotel) 
7205118ebe8SLucas Mateus Castro (alqotel)     mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
72156964585SCédric Le Goater      qemu_log_mask(CPU_LOG_MMU, "%s: TLB ADDR=0x" TARGET_FMT_lx
72256964585SCédric Le Goater                    " PID=0x%x MAS1=0x%x MAS2=0x%" PRIx64 " mask=0x%"
72356964585SCédric Le Goater                    HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%" PRIx32 "\n",
72456964585SCédric Le Goater                    __func__, address, pid, tlb->mas1, tlb->mas2, mask,
7255118ebe8SLucas Mateus Castro (alqotel)                    tlb->mas7_3, tlb->mas8);
7265118ebe8SLucas Mateus Castro (alqotel) 
7275118ebe8SLucas Mateus Castro (alqotel)     /* Check PID */
7285118ebe8SLucas Mateus Castro (alqotel)     tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
7295118ebe8SLucas Mateus Castro (alqotel)     if (tlb_pid != 0 && tlb_pid != pid) {
7305118ebe8SLucas Mateus Castro (alqotel)         return -1;
7315118ebe8SLucas Mateus Castro (alqotel)     }
7325118ebe8SLucas Mateus Castro (alqotel) 
7335118ebe8SLucas Mateus Castro (alqotel)     /* Check effective address */
7345118ebe8SLucas Mateus Castro (alqotel)     if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
7355118ebe8SLucas Mateus Castro (alqotel)         return -1;
7365118ebe8SLucas Mateus Castro (alqotel)     }
7375118ebe8SLucas Mateus Castro (alqotel) 
7385118ebe8SLucas Mateus Castro (alqotel)     if (raddrp) {
7395118ebe8SLucas Mateus Castro (alqotel)         *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
7405118ebe8SLucas Mateus Castro (alqotel)     }
7415118ebe8SLucas Mateus Castro (alqotel) 
7425118ebe8SLucas Mateus Castro (alqotel)     return 0;
7435118ebe8SLucas Mateus Castro (alqotel) }
7445118ebe8SLucas Mateus Castro (alqotel) 
7455118ebe8SLucas Mateus Castro (alqotel) static bool is_epid_mmu(int mmu_idx)
7465118ebe8SLucas Mateus Castro (alqotel) {
7475118ebe8SLucas Mateus Castro (alqotel)     return mmu_idx == PPC_TLB_EPID_STORE || mmu_idx == PPC_TLB_EPID_LOAD;
7485118ebe8SLucas Mateus Castro (alqotel) }
7495118ebe8SLucas Mateus Castro (alqotel) 
7505118ebe8SLucas Mateus Castro (alqotel) static uint32_t mmubooke206_esr(int mmu_idx, MMUAccessType access_type)
7515118ebe8SLucas Mateus Castro (alqotel) {
7525118ebe8SLucas Mateus Castro (alqotel)     uint32_t esr = 0;
7535118ebe8SLucas Mateus Castro (alqotel)     if (access_type == MMU_DATA_STORE) {
7545118ebe8SLucas Mateus Castro (alqotel)         esr |= ESR_ST;
7555118ebe8SLucas Mateus Castro (alqotel)     }
7565118ebe8SLucas Mateus Castro (alqotel)     if (is_epid_mmu(mmu_idx)) {
7575118ebe8SLucas Mateus Castro (alqotel)         esr |= ESR_EPID;
7585118ebe8SLucas Mateus Castro (alqotel)     }
7595118ebe8SLucas Mateus Castro (alqotel)     return esr;
7605118ebe8SLucas Mateus Castro (alqotel) }
7615118ebe8SLucas Mateus Castro (alqotel) 
7625118ebe8SLucas Mateus Castro (alqotel) /*
7635118ebe8SLucas Mateus Castro (alqotel)  * Get EPID register given the mmu_idx. If this is regular load,
7645118ebe8SLucas Mateus Castro (alqotel)  * construct the EPID access bits from current processor state
7655118ebe8SLucas Mateus Castro (alqotel)  *
7665118ebe8SLucas Mateus Castro (alqotel)  * Get the effective AS and PR bits and the PID. The PID is returned
7675118ebe8SLucas Mateus Castro (alqotel)  * only if EPID load is requested, otherwise the caller must detect
7685118ebe8SLucas Mateus Castro (alqotel)  * the correct EPID.  Return true if valid EPID is returned.
7695118ebe8SLucas Mateus Castro (alqotel)  */
7705118ebe8SLucas Mateus Castro (alqotel) static bool mmubooke206_get_as(CPUPPCState *env,
7715118ebe8SLucas Mateus Castro (alqotel)                                int mmu_idx, uint32_t *epid_out,
7725118ebe8SLucas Mateus Castro (alqotel)                                bool *as_out, bool *pr_out)
7735118ebe8SLucas Mateus Castro (alqotel) {
7745118ebe8SLucas Mateus Castro (alqotel)     if (is_epid_mmu(mmu_idx)) {
7755118ebe8SLucas Mateus Castro (alqotel)         uint32_t epidr;
7765118ebe8SLucas Mateus Castro (alqotel)         if (mmu_idx == PPC_TLB_EPID_STORE) {
7775118ebe8SLucas Mateus Castro (alqotel)             epidr = env->spr[SPR_BOOKE_EPSC];
7785118ebe8SLucas Mateus Castro (alqotel)         } else {
7795118ebe8SLucas Mateus Castro (alqotel)             epidr = env->spr[SPR_BOOKE_EPLC];
7805118ebe8SLucas Mateus Castro (alqotel)         }
7815118ebe8SLucas Mateus Castro (alqotel)         *epid_out = (epidr & EPID_EPID) >> EPID_EPID_SHIFT;
7825118ebe8SLucas Mateus Castro (alqotel)         *as_out = !!(epidr & EPID_EAS);
7835118ebe8SLucas Mateus Castro (alqotel)         *pr_out = !!(epidr & EPID_EPR);
7845118ebe8SLucas Mateus Castro (alqotel)         return true;
7855118ebe8SLucas Mateus Castro (alqotel)     } else {
78626363616SVíctor Colombo         *as_out = FIELD_EX64(env->msr, MSR, DS);
787d41ccf6eSVíctor Colombo         *pr_out = FIELD_EX64(env->msr, MSR, PR);
7885118ebe8SLucas Mateus Castro (alqotel)         return false;
7895118ebe8SLucas Mateus Castro (alqotel)     }
7905118ebe8SLucas Mateus Castro (alqotel) }
7915118ebe8SLucas Mateus Castro (alqotel) 
7925118ebe8SLucas Mateus Castro (alqotel) /* Check if the tlb found by hashing really matches */
7935118ebe8SLucas Mateus Castro (alqotel) static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
7945118ebe8SLucas Mateus Castro (alqotel)                                  hwaddr *raddr, int *prot,
7955118ebe8SLucas Mateus Castro (alqotel)                                  target_ulong address,
7965118ebe8SLucas Mateus Castro (alqotel)                                  MMUAccessType access_type, int mmu_idx)
7975118ebe8SLucas Mateus Castro (alqotel) {
7985118ebe8SLucas Mateus Castro (alqotel)     int prot2 = 0;
7995118ebe8SLucas Mateus Castro (alqotel)     uint32_t epid;
8005118ebe8SLucas Mateus Castro (alqotel)     bool as, pr;
8015118ebe8SLucas Mateus Castro (alqotel)     bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
8025118ebe8SLucas Mateus Castro (alqotel) 
8035118ebe8SLucas Mateus Castro (alqotel)     if (!use_epid) {
8045118ebe8SLucas Mateus Castro (alqotel)         if (ppcmas_tlb_check(env, tlb, raddr, address,
8055118ebe8SLucas Mateus Castro (alqotel)                              env->spr[SPR_BOOKE_PID]) >= 0) {
8065118ebe8SLucas Mateus Castro (alqotel)             goto found_tlb;
8075118ebe8SLucas Mateus Castro (alqotel)         }
8085118ebe8SLucas Mateus Castro (alqotel) 
8095118ebe8SLucas Mateus Castro (alqotel)         if (env->spr[SPR_BOOKE_PID1] &&
8105118ebe8SLucas Mateus Castro (alqotel)             ppcmas_tlb_check(env, tlb, raddr, address,
8115118ebe8SLucas Mateus Castro (alqotel)                              env->spr[SPR_BOOKE_PID1]) >= 0) {
8125118ebe8SLucas Mateus Castro (alqotel)             goto found_tlb;
8135118ebe8SLucas Mateus Castro (alqotel)         }
8145118ebe8SLucas Mateus Castro (alqotel) 
8155118ebe8SLucas Mateus Castro (alqotel)         if (env->spr[SPR_BOOKE_PID2] &&
8165118ebe8SLucas Mateus Castro (alqotel)             ppcmas_tlb_check(env, tlb, raddr, address,
8175118ebe8SLucas Mateus Castro (alqotel)                              env->spr[SPR_BOOKE_PID2]) >= 0) {
8185118ebe8SLucas Mateus Castro (alqotel)             goto found_tlb;
8195118ebe8SLucas Mateus Castro (alqotel)         }
8205118ebe8SLucas Mateus Castro (alqotel)     } else {
8215118ebe8SLucas Mateus Castro (alqotel)         if (ppcmas_tlb_check(env, tlb, raddr, address, epid) >= 0) {
8225118ebe8SLucas Mateus Castro (alqotel)             goto found_tlb;
8235118ebe8SLucas Mateus Castro (alqotel)         }
8245118ebe8SLucas Mateus Castro (alqotel)     }
8255118ebe8SLucas Mateus Castro (alqotel) 
826e4cadfbeSBernhard Beschow     qemu_log_mask(CPU_LOG_MMU, "%s: No TLB entry found for effective address "
827e4cadfbeSBernhard Beschow                   "0x" TARGET_FMT_lx "\n", __func__, address);
8285118ebe8SLucas Mateus Castro (alqotel)     return -1;
8295118ebe8SLucas Mateus Castro (alqotel) 
8305118ebe8SLucas Mateus Castro (alqotel) found_tlb:
8315118ebe8SLucas Mateus Castro (alqotel) 
8325118ebe8SLucas Mateus Castro (alqotel)     if (pr) {
8335118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_UR) {
8345118ebe8SLucas Mateus Castro (alqotel)             prot2 |= PAGE_READ;
8355118ebe8SLucas Mateus Castro (alqotel)         }
8365118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_UW) {
8375118ebe8SLucas Mateus Castro (alqotel)             prot2 |= PAGE_WRITE;
8385118ebe8SLucas Mateus Castro (alqotel)         }
8395118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_UX) {
8405118ebe8SLucas Mateus Castro (alqotel)             prot2 |= PAGE_EXEC;
8415118ebe8SLucas Mateus Castro (alqotel)         }
8425118ebe8SLucas Mateus Castro (alqotel)     } else {
8435118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_SR) {
8445118ebe8SLucas Mateus Castro (alqotel)             prot2 |= PAGE_READ;
8455118ebe8SLucas Mateus Castro (alqotel)         }
8465118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_SW) {
8475118ebe8SLucas Mateus Castro (alqotel)             prot2 |= PAGE_WRITE;
8485118ebe8SLucas Mateus Castro (alqotel)         }
8495118ebe8SLucas Mateus Castro (alqotel)         if (tlb->mas7_3 & MAS3_SX) {
8505118ebe8SLucas Mateus Castro (alqotel)             prot2 |= PAGE_EXEC;
8515118ebe8SLucas Mateus Castro (alqotel)         }
8525118ebe8SLucas Mateus Castro (alqotel)     }
8535118ebe8SLucas Mateus Castro (alqotel) 
8545118ebe8SLucas Mateus Castro (alqotel)     /* Check the address space and permissions */
8555118ebe8SLucas Mateus Castro (alqotel)     if (access_type == MMU_INST_FETCH) {
8565118ebe8SLucas Mateus Castro (alqotel)         /* There is no way to fetch code using epid load */
8575118ebe8SLucas Mateus Castro (alqotel)         assert(!use_epid);
8584d979c9fSVíctor Colombo         as = FIELD_EX64(env->msr, MSR, IR);
8595118ebe8SLucas Mateus Castro (alqotel)     }
8605118ebe8SLucas Mateus Castro (alqotel) 
8615118ebe8SLucas Mateus Castro (alqotel)     if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
86256964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
8635118ebe8SLucas Mateus Castro (alqotel)         return -1;
8645118ebe8SLucas Mateus Castro (alqotel)     }
8655118ebe8SLucas Mateus Castro (alqotel) 
8665118ebe8SLucas Mateus Castro (alqotel)     *prot = prot2;
8675118ebe8SLucas Mateus Castro (alqotel)     if (prot2 & prot_for_access_type(access_type)) {
86856964585SCédric Le Goater         qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
8695118ebe8SLucas Mateus Castro (alqotel)         return 0;
8705118ebe8SLucas Mateus Castro (alqotel)     }
8715118ebe8SLucas Mateus Castro (alqotel) 
87256964585SCédric Le Goater     qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, prot2);
8735118ebe8SLucas Mateus Castro (alqotel)     return access_type == MMU_INST_FETCH ? -3 : -2;
8745118ebe8SLucas Mateus Castro (alqotel) }
8755118ebe8SLucas Mateus Castro (alqotel) 
8765118ebe8SLucas Mateus Castro (alqotel) static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
8775118ebe8SLucas Mateus Castro (alqotel)                                             target_ulong address,
8785118ebe8SLucas Mateus Castro (alqotel)                                             MMUAccessType access_type,
8795118ebe8SLucas Mateus Castro (alqotel)                                             int mmu_idx)
8805118ebe8SLucas Mateus Castro (alqotel) {
8815118ebe8SLucas Mateus Castro (alqotel)     ppcmas_tlb_t *tlb;
8825118ebe8SLucas Mateus Castro (alqotel)     hwaddr raddr;
8835118ebe8SLucas Mateus Castro (alqotel)     int i, j, ret;
8845118ebe8SLucas Mateus Castro (alqotel) 
8855118ebe8SLucas Mateus Castro (alqotel)     ret = -1;
8865118ebe8SLucas Mateus Castro (alqotel)     raddr = (hwaddr)-1ULL;
8875118ebe8SLucas Mateus Castro (alqotel) 
8885118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
8895118ebe8SLucas Mateus Castro (alqotel)         int ways = booke206_tlb_ways(env, i);
8905118ebe8SLucas Mateus Castro (alqotel) 
8915118ebe8SLucas Mateus Castro (alqotel)         for (j = 0; j < ways; j++) {
8925118ebe8SLucas Mateus Castro (alqotel)             tlb = booke206_get_tlbm(env, i, address, j);
8935118ebe8SLucas Mateus Castro (alqotel)             if (!tlb) {
8945118ebe8SLucas Mateus Castro (alqotel)                 continue;
8955118ebe8SLucas Mateus Castro (alqotel)             }
8965118ebe8SLucas Mateus Castro (alqotel)             ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
8975118ebe8SLucas Mateus Castro (alqotel)                                         access_type, mmu_idx);
8985118ebe8SLucas Mateus Castro (alqotel)             if (ret != -1) {
8995118ebe8SLucas Mateus Castro (alqotel)                 goto found_tlb;
9005118ebe8SLucas Mateus Castro (alqotel)             }
9015118ebe8SLucas Mateus Castro (alqotel)         }
9025118ebe8SLucas Mateus Castro (alqotel)     }
9035118ebe8SLucas Mateus Castro (alqotel) 
9045118ebe8SLucas Mateus Castro (alqotel) found_tlb:
9055118ebe8SLucas Mateus Castro (alqotel) 
9065118ebe8SLucas Mateus Castro (alqotel)     if (ret >= 0) {
9075118ebe8SLucas Mateus Castro (alqotel)         ctx->raddr = raddr;
90856964585SCédric Le Goater          qemu_log_mask(CPU_LOG_MMU, "%s: access granted " TARGET_FMT_lx
909883f2c59SPhilippe Mathieu-Daudé                        " => " HWADDR_FMT_plx " %d %d\n", __func__, address,
91056964585SCédric Le Goater                        ctx->raddr, ctx->prot, ret);
9115118ebe8SLucas Mateus Castro (alqotel)     } else {
91256964585SCédric Le Goater          qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx
913883f2c59SPhilippe Mathieu-Daudé                        " => " HWADDR_FMT_plx " %d %d\n", __func__, address,
91456964585SCédric Le Goater                        raddr, ctx->prot, ret);
9155118ebe8SLucas Mateus Castro (alqotel)     }
9165118ebe8SLucas Mateus Castro (alqotel) 
9175118ebe8SLucas Mateus Castro (alqotel)     return ret;
9185118ebe8SLucas Mateus Castro (alqotel) }
9195118ebe8SLucas Mateus Castro (alqotel) 
9205118ebe8SLucas Mateus Castro (alqotel) static const char *book3e_tsize_to_str[32] = {
9215118ebe8SLucas Mateus Castro (alqotel)     "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
9225118ebe8SLucas Mateus Castro (alqotel)     "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
9235118ebe8SLucas Mateus Castro (alqotel)     "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
9245118ebe8SLucas Mateus Castro (alqotel)     "1T", "2T"
9255118ebe8SLucas Mateus Castro (alqotel) };
9265118ebe8SLucas Mateus Castro (alqotel) 
9275118ebe8SLucas Mateus Castro (alqotel) static void mmubooke_dump_mmu(CPUPPCState *env)
9285118ebe8SLucas Mateus Castro (alqotel) {
9295118ebe8SLucas Mateus Castro (alqotel)     ppcemb_tlb_t *entry;
9305118ebe8SLucas Mateus Castro (alqotel)     int i;
9315118ebe8SLucas Mateus Castro (alqotel) 
93205739977SPhilippe Mathieu-Daudé #ifdef CONFIG_KVM
9335118ebe8SLucas Mateus Castro (alqotel)     if (kvm_enabled() && !env->kvm_sw_tlb) {
9345118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("Cannot access KVM TLB\n");
9355118ebe8SLucas Mateus Castro (alqotel)         return;
9365118ebe8SLucas Mateus Castro (alqotel)     }
93705739977SPhilippe Mathieu-Daudé #endif
9385118ebe8SLucas Mateus Castro (alqotel) 
9395118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nTLB:\n");
9405118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("Effective          Physical           Size PID   Prot     "
9415118ebe8SLucas Mateus Castro (alqotel)                 "Attr\n");
9425118ebe8SLucas Mateus Castro (alqotel) 
9435118ebe8SLucas Mateus Castro (alqotel)     entry = &env->tlb.tlbe[0];
9445118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_tlb; i++, entry++) {
9455118ebe8SLucas Mateus Castro (alqotel)         hwaddr ea, pa;
9465118ebe8SLucas Mateus Castro (alqotel)         target_ulong mask;
9475118ebe8SLucas Mateus Castro (alqotel)         uint64_t size = (uint64_t)entry->size;
9485118ebe8SLucas Mateus Castro (alqotel)         char size_buf[20];
9495118ebe8SLucas Mateus Castro (alqotel) 
9505118ebe8SLucas Mateus Castro (alqotel)         /* Check valid flag */
9515118ebe8SLucas Mateus Castro (alqotel)         if (!(entry->prot & PAGE_VALID)) {
9525118ebe8SLucas Mateus Castro (alqotel)             continue;
9535118ebe8SLucas Mateus Castro (alqotel)         }
9545118ebe8SLucas Mateus Castro (alqotel) 
9555118ebe8SLucas Mateus Castro (alqotel)         mask = ~(entry->size - 1);
9565118ebe8SLucas Mateus Castro (alqotel)         ea = entry->EPN & mask;
9575118ebe8SLucas Mateus Castro (alqotel)         pa = entry->RPN & mask;
9585118ebe8SLucas Mateus Castro (alqotel)         /* Extend the physical address to 36 bits */
9595118ebe8SLucas Mateus Castro (alqotel)         pa |= (hwaddr)(entry->RPN & 0xF) << 32;
9605118ebe8SLucas Mateus Castro (alqotel)         if (size >= 1 * MiB) {
9615118ebe8SLucas Mateus Castro (alqotel)             snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / MiB);
9625118ebe8SLucas Mateus Castro (alqotel)         } else {
9635118ebe8SLucas Mateus Castro (alqotel)             snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size / KiB);
9645118ebe8SLucas Mateus Castro (alqotel)         }
9655118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
9665118ebe8SLucas Mateus Castro (alqotel)                     (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
9675118ebe8SLucas Mateus Castro (alqotel)                     entry->prot, entry->attr);
9685118ebe8SLucas Mateus Castro (alqotel)     }
9695118ebe8SLucas Mateus Castro (alqotel) 
9705118ebe8SLucas Mateus Castro (alqotel) }
9715118ebe8SLucas Mateus Castro (alqotel) 
9725118ebe8SLucas Mateus Castro (alqotel) static void mmubooke206_dump_one_tlb(CPUPPCState *env, int tlbn, int offset,
9735118ebe8SLucas Mateus Castro (alqotel)                                      int tlbsize)
9745118ebe8SLucas Mateus Castro (alqotel) {
9755118ebe8SLucas Mateus Castro (alqotel)     ppcmas_tlb_t *entry;
9765118ebe8SLucas Mateus Castro (alqotel)     int i;
9775118ebe8SLucas Mateus Castro (alqotel) 
9785118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nTLB%d:\n", tlbn);
9795118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("Effective          Physical           Size TID   TS SRWX"
9805118ebe8SLucas Mateus Castro (alqotel)                 " URWX WIMGE U0123\n");
9815118ebe8SLucas Mateus Castro (alqotel) 
9825118ebe8SLucas Mateus Castro (alqotel)     entry = &env->tlb.tlbm[offset];
9835118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < tlbsize; i++, entry++) {
9845118ebe8SLucas Mateus Castro (alqotel)         hwaddr ea, pa, size;
9855118ebe8SLucas Mateus Castro (alqotel)         int tsize;
9865118ebe8SLucas Mateus Castro (alqotel) 
9875118ebe8SLucas Mateus Castro (alqotel)         if (!(entry->mas1 & MAS1_VALID)) {
9885118ebe8SLucas Mateus Castro (alqotel)             continue;
9895118ebe8SLucas Mateus Castro (alqotel)         }
9905118ebe8SLucas Mateus Castro (alqotel) 
9915118ebe8SLucas Mateus Castro (alqotel)         tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
9925118ebe8SLucas Mateus Castro (alqotel)         size = 1024ULL << tsize;
9935118ebe8SLucas Mateus Castro (alqotel)         ea = entry->mas2 & ~(size - 1);
9945118ebe8SLucas Mateus Castro (alqotel)         pa = entry->mas7_3 & ~(size - 1);
9955118ebe8SLucas Mateus Castro (alqotel) 
9965118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u  S%c%c%c"
9975118ebe8SLucas Mateus Castro (alqotel)                     " U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
9985118ebe8SLucas Mateus Castro (alqotel)                     (uint64_t)ea, (uint64_t)pa,
9995118ebe8SLucas Mateus Castro (alqotel)                     book3e_tsize_to_str[tsize],
10005118ebe8SLucas Mateus Castro (alqotel)                     (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
10015118ebe8SLucas Mateus Castro (alqotel)                     (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
10025118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_SR ? 'R' : '-',
10035118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_SW ? 'W' : '-',
10045118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_SX ? 'X' : '-',
10055118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_UR ? 'R' : '-',
10065118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_UW ? 'W' : '-',
10075118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_UX ? 'X' : '-',
10085118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_W ? 'W' : '-',
10095118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_I ? 'I' : '-',
10105118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_M ? 'M' : '-',
10115118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_G ? 'G' : '-',
10125118ebe8SLucas Mateus Castro (alqotel)                     entry->mas2 & MAS2_E ? 'E' : '-',
10135118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U0 ? '0' : '-',
10145118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U1 ? '1' : '-',
10155118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U2 ? '2' : '-',
10165118ebe8SLucas Mateus Castro (alqotel)                     entry->mas7_3 & MAS3_U3 ? '3' : '-');
10175118ebe8SLucas Mateus Castro (alqotel)     }
10185118ebe8SLucas Mateus Castro (alqotel) }
10195118ebe8SLucas Mateus Castro (alqotel) 
10205118ebe8SLucas Mateus Castro (alqotel) static void mmubooke206_dump_mmu(CPUPPCState *env)
10215118ebe8SLucas Mateus Castro (alqotel) {
10225118ebe8SLucas Mateus Castro (alqotel)     int offset = 0;
10235118ebe8SLucas Mateus Castro (alqotel)     int i;
10245118ebe8SLucas Mateus Castro (alqotel) 
102505739977SPhilippe Mathieu-Daudé #ifdef CONFIG_KVM
10265118ebe8SLucas Mateus Castro (alqotel)     if (kvm_enabled() && !env->kvm_sw_tlb) {
10275118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("Cannot access KVM TLB\n");
10285118ebe8SLucas Mateus Castro (alqotel)         return;
10295118ebe8SLucas Mateus Castro (alqotel)     }
103005739977SPhilippe Mathieu-Daudé #endif
10315118ebe8SLucas Mateus Castro (alqotel) 
10325118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
10335118ebe8SLucas Mateus Castro (alqotel)         int size = booke206_tlb_size(env, i);
10345118ebe8SLucas Mateus Castro (alqotel) 
10355118ebe8SLucas Mateus Castro (alqotel)         if (size == 0) {
10365118ebe8SLucas Mateus Castro (alqotel)             continue;
10375118ebe8SLucas Mateus Castro (alqotel)         }
10385118ebe8SLucas Mateus Castro (alqotel) 
10395118ebe8SLucas Mateus Castro (alqotel)         mmubooke206_dump_one_tlb(env, i, offset, size);
10405118ebe8SLucas Mateus Castro (alqotel)         offset += size;
10415118ebe8SLucas Mateus Castro (alqotel)     }
10425118ebe8SLucas Mateus Castro (alqotel) }
10435118ebe8SLucas Mateus Castro (alqotel) 
10445118ebe8SLucas Mateus Castro (alqotel) static void mmu6xx_dump_BATs(CPUPPCState *env, int type)
10455118ebe8SLucas Mateus Castro (alqotel) {
10465118ebe8SLucas Mateus Castro (alqotel)     target_ulong *BATlt, *BATut, *BATu, *BATl;
10475118ebe8SLucas Mateus Castro (alqotel)     target_ulong BEPIl, BEPIu, bl;
10485118ebe8SLucas Mateus Castro (alqotel)     int i;
10495118ebe8SLucas Mateus Castro (alqotel) 
10505118ebe8SLucas Mateus Castro (alqotel)     switch (type) {
10515118ebe8SLucas Mateus Castro (alqotel)     case ACCESS_CODE:
10525118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->IBAT[1];
10535118ebe8SLucas Mateus Castro (alqotel)         BATut = env->IBAT[0];
10545118ebe8SLucas Mateus Castro (alqotel)         break;
10555118ebe8SLucas Mateus Castro (alqotel)     default:
10565118ebe8SLucas Mateus Castro (alqotel)         BATlt = env->DBAT[1];
10575118ebe8SLucas Mateus Castro (alqotel)         BATut = env->DBAT[0];
10585118ebe8SLucas Mateus Castro (alqotel)         break;
10595118ebe8SLucas Mateus Castro (alqotel)     }
10605118ebe8SLucas Mateus Castro (alqotel) 
10615118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < env->nb_BATs; i++) {
10625118ebe8SLucas Mateus Castro (alqotel)         BATu = &BATut[i];
10635118ebe8SLucas Mateus Castro (alqotel)         BATl = &BATlt[i];
10645118ebe8SLucas Mateus Castro (alqotel)         BEPIu = *BATu & 0xF0000000;
10655118ebe8SLucas Mateus Castro (alqotel)         BEPIl = *BATu & 0x0FFE0000;
10665118ebe8SLucas Mateus Castro (alqotel)         bl = (*BATu & 0x00001FFC) << 15;
10675118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("%s BAT%d BATu " TARGET_FMT_lx
10685118ebe8SLucas Mateus Castro (alqotel)                     " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
10695118ebe8SLucas Mateus Castro (alqotel)                     TARGET_FMT_lx " " TARGET_FMT_lx "\n",
10705118ebe8SLucas Mateus Castro (alqotel)                     type == ACCESS_CODE ? "code" : "data", i,
10715118ebe8SLucas Mateus Castro (alqotel)                     *BATu, *BATl, BEPIu, BEPIl, bl);
10725118ebe8SLucas Mateus Castro (alqotel)     }
10735118ebe8SLucas Mateus Castro (alqotel) }
10745118ebe8SLucas Mateus Castro (alqotel) 
10755118ebe8SLucas Mateus Castro (alqotel) static void mmu6xx_dump_mmu(CPUPPCState *env)
10765118ebe8SLucas Mateus Castro (alqotel) {
10775118ebe8SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = env_archcpu(env);
10785118ebe8SLucas Mateus Castro (alqotel)     ppc6xx_tlb_t *tlb;
10795118ebe8SLucas Mateus Castro (alqotel)     target_ulong sr;
10805118ebe8SLucas Mateus Castro (alqotel)     int type, way, entry, i;
10815118ebe8SLucas Mateus Castro (alqotel) 
10825118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu));
10835118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu));
10845118ebe8SLucas Mateus Castro (alqotel) 
10855118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nSegment registers:\n");
10865118ebe8SLucas Mateus Castro (alqotel)     for (i = 0; i < 32; i++) {
10875118ebe8SLucas Mateus Castro (alqotel)         sr = env->sr[i];
10885118ebe8SLucas Mateus Castro (alqotel)         if (sr & 0x80000000) {
10895118ebe8SLucas Mateus Castro (alqotel)             qemu_printf("%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
10905118ebe8SLucas Mateus Castro (alqotel)                         "CNTLR_SPEC=0x%05x\n", i,
10915118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
10925118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
10935118ebe8SLucas Mateus Castro (alqotel)                         (uint32_t)(sr & 0xFFFFF));
10945118ebe8SLucas Mateus Castro (alqotel)         } else {
10955118ebe8SLucas Mateus Castro (alqotel)             qemu_printf("%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
10965118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
10975118ebe8SLucas Mateus Castro (alqotel)                         sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
10985118ebe8SLucas Mateus Castro (alqotel)                         (uint32_t)(sr & 0x00FFFFFF));
10995118ebe8SLucas Mateus Castro (alqotel)         }
11005118ebe8SLucas Mateus Castro (alqotel)     }
11015118ebe8SLucas Mateus Castro (alqotel) 
11025118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nBATs:\n");
11035118ebe8SLucas Mateus Castro (alqotel)     mmu6xx_dump_BATs(env, ACCESS_INT);
11045118ebe8SLucas Mateus Castro (alqotel)     mmu6xx_dump_BATs(env, ACCESS_CODE);
11055118ebe8SLucas Mateus Castro (alqotel) 
11065118ebe8SLucas Mateus Castro (alqotel)     if (env->id_tlbs != 1) {
11075118ebe8SLucas Mateus Castro (alqotel)         qemu_printf("ERROR: 6xx MMU should have separated TLB"
11085118ebe8SLucas Mateus Castro (alqotel)                     " for code and data\n");
11095118ebe8SLucas Mateus Castro (alqotel)     }
11105118ebe8SLucas Mateus Castro (alqotel) 
11115118ebe8SLucas Mateus Castro (alqotel)     qemu_printf("\nTLBs                       [EPN    EPN + SIZE]\n");
11125118ebe8SLucas Mateus Castro (alqotel) 
11135118ebe8SLucas Mateus Castro (alqotel)     for (type = 0; type < 2; type++) {
11145118ebe8SLucas Mateus Castro (alqotel)         for (way = 0; way < env->nb_ways; way++) {
11155118ebe8SLucas Mateus Castro (alqotel)             for (entry = env->nb_tlb * type + env->tlb_per_way * way;
11165118ebe8SLucas Mateus Castro (alqotel)                  entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
11175118ebe8SLucas Mateus Castro (alqotel)                  entry++) {
11185118ebe8SLucas Mateus Castro (alqotel) 
11195118ebe8SLucas Mateus Castro (alqotel)                 tlb = &env->tlb.tlb6[entry];
11205118ebe8SLucas Mateus Castro (alqotel)                 qemu_printf("%s TLB %02d/%02d way:%d %s ["
11215118ebe8SLucas Mateus Castro (alqotel)                             TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
11225118ebe8SLucas Mateus Castro (alqotel)                             type ? "code" : "data", entry % env->nb_tlb,
11235118ebe8SLucas Mateus Castro (alqotel)                             env->nb_tlb, way,
11245118ebe8SLucas Mateus Castro (alqotel)                             pte_is_valid(tlb->pte0) ? "valid" : "inval",
11255118ebe8SLucas Mateus Castro (alqotel)                             tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
11265118ebe8SLucas Mateus Castro (alqotel)             }
11275118ebe8SLucas Mateus Castro (alqotel)         }
11285118ebe8SLucas Mateus Castro (alqotel)     }
11295118ebe8SLucas Mateus Castro (alqotel) }
11305118ebe8SLucas Mateus Castro (alqotel) 
11315118ebe8SLucas Mateus Castro (alqotel) void dump_mmu(CPUPPCState *env)
11325118ebe8SLucas Mateus Castro (alqotel) {
11335118ebe8SLucas Mateus Castro (alqotel)     switch (env->mmu_model) {
11345118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_BOOKE:
11355118ebe8SLucas Mateus Castro (alqotel)         mmubooke_dump_mmu(env);
11365118ebe8SLucas Mateus Castro (alqotel)         break;
11375118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_BOOKE206:
11385118ebe8SLucas Mateus Castro (alqotel)         mmubooke206_dump_mmu(env);
11395118ebe8SLucas Mateus Castro (alqotel)         break;
11405118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_SOFT_6xx:
11415118ebe8SLucas Mateus Castro (alqotel)         mmu6xx_dump_mmu(env);
11425118ebe8SLucas Mateus Castro (alqotel)         break;
11435118ebe8SLucas Mateus Castro (alqotel) #if defined(TARGET_PPC64)
11445118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_64B:
11455118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_03:
11465118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_06:
11475118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_07:
11485118ebe8SLucas Mateus Castro (alqotel)         dump_slb(env_archcpu(env));
11495118ebe8SLucas Mateus Castro (alqotel)         break;
11505118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_3_00:
11515118ebe8SLucas Mateus Castro (alqotel)         if (ppc64_v3_radix(env_archcpu(env))) {
11525118ebe8SLucas Mateus Castro (alqotel)             qemu_log_mask(LOG_UNIMP, "%s: the PPC64 MMU is unsupported\n",
11535118ebe8SLucas Mateus Castro (alqotel)                           __func__);
11545118ebe8SLucas Mateus Castro (alqotel)         } else {
11555118ebe8SLucas Mateus Castro (alqotel)             dump_slb(env_archcpu(env));
11565118ebe8SLucas Mateus Castro (alqotel)         }
11575118ebe8SLucas Mateus Castro (alqotel)         break;
11585118ebe8SLucas Mateus Castro (alqotel) #endif
11595118ebe8SLucas Mateus Castro (alqotel)     default:
11605118ebe8SLucas Mateus Castro (alqotel)         qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
11615118ebe8SLucas Mateus Castro (alqotel)     }
11625118ebe8SLucas Mateus Castro (alqotel) }
11635118ebe8SLucas Mateus Castro (alqotel) 
11645118ebe8SLucas Mateus Castro (alqotel) static int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr,
11655118ebe8SLucas Mateus Castro (alqotel)                           MMUAccessType access_type)
11665118ebe8SLucas Mateus Castro (alqotel) {
11675118ebe8SLucas Mateus Castro (alqotel)     ctx->raddr = eaddr;
11685118ebe8SLucas Mateus Castro (alqotel)     ctx->prot = PAGE_READ | PAGE_EXEC;
1169c8f49e6bSCédric Le Goater 
11705118ebe8SLucas Mateus Castro (alqotel)     switch (env->mmu_model) {
11715118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_SOFT_6xx:
11725118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_SOFT_4xx:
11735118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_REAL:
11745118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_BOOKE:
11755118ebe8SLucas Mateus Castro (alqotel)         ctx->prot |= PAGE_WRITE;
11765118ebe8SLucas Mateus Castro (alqotel)         break;
11775118ebe8SLucas Mateus Castro (alqotel) 
11785118ebe8SLucas Mateus Castro (alqotel)     default:
11795118ebe8SLucas Mateus Castro (alqotel)         /* Caller's checks mean we should never get here for other models */
1180c8f49e6bSCédric Le Goater         g_assert_not_reached();
11815118ebe8SLucas Mateus Castro (alqotel)     }
11825118ebe8SLucas Mateus Castro (alqotel) 
1183c8f49e6bSCédric Le Goater     return 0;
11845118ebe8SLucas Mateus Castro (alqotel) }
11855118ebe8SLucas Mateus Castro (alqotel) 
11865118ebe8SLucas Mateus Castro (alqotel) int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx,
11875118ebe8SLucas Mateus Castro (alqotel)                                      target_ulong eaddr,
11885118ebe8SLucas Mateus Castro (alqotel)                                      MMUAccessType access_type, int type,
11895118ebe8SLucas Mateus Castro (alqotel)                                      int mmu_idx)
11905118ebe8SLucas Mateus Castro (alqotel) {
11915118ebe8SLucas Mateus Castro (alqotel)     int ret = -1;
1192e4eea6efSVíctor Colombo     bool real_mode = (type == ACCESS_CODE && !FIELD_EX64(env->msr, MSR, IR)) ||
1193e4eea6efSVíctor Colombo                      (type != ACCESS_CODE && !FIELD_EX64(env->msr, MSR, DR));
11945118ebe8SLucas Mateus Castro (alqotel) 
11955118ebe8SLucas Mateus Castro (alqotel)     switch (env->mmu_model) {
11965118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_SOFT_6xx:
11975118ebe8SLucas Mateus Castro (alqotel)         if (real_mode) {
11985118ebe8SLucas Mateus Castro (alqotel)             ret = check_physical(env, ctx, eaddr, access_type);
11995118ebe8SLucas Mateus Castro (alqotel)         } else {
12005118ebe8SLucas Mateus Castro (alqotel)             /* Try to find a BAT */
12015118ebe8SLucas Mateus Castro (alqotel)             if (env->nb_BATs != 0) {
12025118ebe8SLucas Mateus Castro (alqotel)                 ret = get_bat_6xx_tlb(env, ctx, eaddr, access_type);
12035118ebe8SLucas Mateus Castro (alqotel)             }
12045118ebe8SLucas Mateus Castro (alqotel)             if (ret < 0) {
12055118ebe8SLucas Mateus Castro (alqotel)                 /* We didn't match any BAT entry or don't have BATs */
12065118ebe8SLucas Mateus Castro (alqotel)                 ret = get_segment_6xx_tlb(env, ctx, eaddr, access_type, type);
12075118ebe8SLucas Mateus Castro (alqotel)             }
12085118ebe8SLucas Mateus Castro (alqotel)         }
12095118ebe8SLucas Mateus Castro (alqotel)         break;
12105118ebe8SLucas Mateus Castro (alqotel) 
12115118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_SOFT_4xx:
12125118ebe8SLucas Mateus Castro (alqotel)         if (real_mode) {
12135118ebe8SLucas Mateus Castro (alqotel)             ret = check_physical(env, ctx, eaddr, access_type);
12145118ebe8SLucas Mateus Castro (alqotel)         } else {
12155118ebe8SLucas Mateus Castro (alqotel)             ret = mmu40x_get_physical_address(env, ctx, eaddr, access_type);
12165118ebe8SLucas Mateus Castro (alqotel)         }
12175118ebe8SLucas Mateus Castro (alqotel)         break;
12185118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_BOOKE:
12195118ebe8SLucas Mateus Castro (alqotel)         ret = mmubooke_get_physical_address(env, ctx, eaddr, access_type);
12205118ebe8SLucas Mateus Castro (alqotel)         break;
12215118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_BOOKE206:
12225118ebe8SLucas Mateus Castro (alqotel)         ret = mmubooke206_get_physical_address(env, ctx, eaddr, access_type,
12235118ebe8SLucas Mateus Castro (alqotel)                                                mmu_idx);
12245118ebe8SLucas Mateus Castro (alqotel)         break;
12255118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_MPC8xx:
12265118ebe8SLucas Mateus Castro (alqotel)         /* XXX: TODO */
12275118ebe8SLucas Mateus Castro (alqotel)         cpu_abort(env_cpu(env), "MPC8xx MMU model is not implemented\n");
12285118ebe8SLucas Mateus Castro (alqotel)         break;
12295118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_REAL:
12305118ebe8SLucas Mateus Castro (alqotel)         if (real_mode) {
12315118ebe8SLucas Mateus Castro (alqotel)             ret = check_physical(env, ctx, eaddr, access_type);
12325118ebe8SLucas Mateus Castro (alqotel)         } else {
12335118ebe8SLucas Mateus Castro (alqotel)             cpu_abort(env_cpu(env),
12345118ebe8SLucas Mateus Castro (alqotel)                       "PowerPC in real mode do not do any translation\n");
12355118ebe8SLucas Mateus Castro (alqotel)         }
12365118ebe8SLucas Mateus Castro (alqotel)         return -1;
12375118ebe8SLucas Mateus Castro (alqotel)     default:
12385118ebe8SLucas Mateus Castro (alqotel)         cpu_abort(env_cpu(env), "Unknown or invalid MMU model\n");
12395118ebe8SLucas Mateus Castro (alqotel)         return -1;
12405118ebe8SLucas Mateus Castro (alqotel)     }
12415118ebe8SLucas Mateus Castro (alqotel) 
12425118ebe8SLucas Mateus Castro (alqotel)     return ret;
12435118ebe8SLucas Mateus Castro (alqotel) }
12445118ebe8SLucas Mateus Castro (alqotel) 
12455118ebe8SLucas Mateus Castro (alqotel) static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
12465118ebe8SLucas Mateus Castro (alqotel)                                          MMUAccessType access_type, int mmu_idx)
12475118ebe8SLucas Mateus Castro (alqotel) {
12485118ebe8SLucas Mateus Castro (alqotel)     uint32_t epid;
12495118ebe8SLucas Mateus Castro (alqotel)     bool as, pr;
12505118ebe8SLucas Mateus Castro (alqotel)     uint32_t missed_tid = 0;
12515118ebe8SLucas Mateus Castro (alqotel)     bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
12525118ebe8SLucas Mateus Castro (alqotel) 
12535118ebe8SLucas Mateus Castro (alqotel)     if (access_type == MMU_INST_FETCH) {
12544d979c9fSVíctor Colombo         as = FIELD_EX64(env->msr, MSR, IR);
12555118ebe8SLucas Mateus Castro (alqotel)     }
12565118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
12575118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
12585118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
12595118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS3] = 0;
12605118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS6] = 0;
12615118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS7] = 0;
12625118ebe8SLucas Mateus Castro (alqotel) 
12635118ebe8SLucas Mateus Castro (alqotel)     /* AS */
12645118ebe8SLucas Mateus Castro (alqotel)     if (as) {
12655118ebe8SLucas Mateus Castro (alqotel)         env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
12665118ebe8SLucas Mateus Castro (alqotel)         env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
12675118ebe8SLucas Mateus Castro (alqotel)     }
12685118ebe8SLucas Mateus Castro (alqotel) 
12695118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
12705118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
12715118ebe8SLucas Mateus Castro (alqotel) 
12725118ebe8SLucas Mateus Castro (alqotel)     if (!use_epid) {
12735118ebe8SLucas Mateus Castro (alqotel)         switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
12745118ebe8SLucas Mateus Castro (alqotel)         case MAS4_TIDSELD_PID0:
12755118ebe8SLucas Mateus Castro (alqotel)             missed_tid = env->spr[SPR_BOOKE_PID];
12765118ebe8SLucas Mateus Castro (alqotel)             break;
12775118ebe8SLucas Mateus Castro (alqotel)         case MAS4_TIDSELD_PID1:
12785118ebe8SLucas Mateus Castro (alqotel)             missed_tid = env->spr[SPR_BOOKE_PID1];
12795118ebe8SLucas Mateus Castro (alqotel)             break;
12805118ebe8SLucas Mateus Castro (alqotel)         case MAS4_TIDSELD_PID2:
12815118ebe8SLucas Mateus Castro (alqotel)             missed_tid = env->spr[SPR_BOOKE_PID2];
12825118ebe8SLucas Mateus Castro (alqotel)             break;
12835118ebe8SLucas Mateus Castro (alqotel)         }
12845118ebe8SLucas Mateus Castro (alqotel)         env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
12855118ebe8SLucas Mateus Castro (alqotel)     } else {
12865118ebe8SLucas Mateus Castro (alqotel)         missed_tid = epid;
12875118ebe8SLucas Mateus Castro (alqotel)         env->spr[SPR_BOOKE_MAS6] |= missed_tid << 16;
12885118ebe8SLucas Mateus Castro (alqotel)     }
12895118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS1] |= (missed_tid << MAS1_TID_SHIFT);
12905118ebe8SLucas Mateus Castro (alqotel) 
12915118ebe8SLucas Mateus Castro (alqotel) 
12925118ebe8SLucas Mateus Castro (alqotel)     /* next victim logic */
12935118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
12945118ebe8SLucas Mateus Castro (alqotel)     env->last_way++;
12955118ebe8SLucas Mateus Castro (alqotel)     env->last_way &= booke206_tlb_ways(env, 0) - 1;
12965118ebe8SLucas Mateus Castro (alqotel)     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
12975118ebe8SLucas Mateus Castro (alqotel) }
12985118ebe8SLucas Mateus Castro (alqotel) 
12995118ebe8SLucas Mateus Castro (alqotel) /* Perform address translation */
13005118ebe8SLucas Mateus Castro (alqotel) /* TODO: Split this by mmu_model. */
13015118ebe8SLucas Mateus Castro (alqotel) static bool ppc_jumbo_xlate(PowerPCCPU *cpu, vaddr eaddr,
13025118ebe8SLucas Mateus Castro (alqotel)                             MMUAccessType access_type,
13035118ebe8SLucas Mateus Castro (alqotel)                             hwaddr *raddrp, int *psizep, int *protp,
13045118ebe8SLucas Mateus Castro (alqotel)                             int mmu_idx, bool guest_visible)
13055118ebe8SLucas Mateus Castro (alqotel) {
13065118ebe8SLucas Mateus Castro (alqotel)     CPUState *cs = CPU(cpu);
13075118ebe8SLucas Mateus Castro (alqotel)     CPUPPCState *env = &cpu->env;
13085118ebe8SLucas Mateus Castro (alqotel)     mmu_ctx_t ctx;
13095118ebe8SLucas Mateus Castro (alqotel)     int type;
13105118ebe8SLucas Mateus Castro (alqotel)     int ret;
13115118ebe8SLucas Mateus Castro (alqotel) 
13125118ebe8SLucas Mateus Castro (alqotel)     if (access_type == MMU_INST_FETCH) {
13135118ebe8SLucas Mateus Castro (alqotel)         /* code access */
13145118ebe8SLucas Mateus Castro (alqotel)         type = ACCESS_CODE;
13155118ebe8SLucas Mateus Castro (alqotel)     } else if (guest_visible) {
13165118ebe8SLucas Mateus Castro (alqotel)         /* data access */
13175118ebe8SLucas Mateus Castro (alqotel)         type = env->access_type;
13185118ebe8SLucas Mateus Castro (alqotel)     } else {
13195118ebe8SLucas Mateus Castro (alqotel)         type = ACCESS_INT;
13205118ebe8SLucas Mateus Castro (alqotel)     }
13215118ebe8SLucas Mateus Castro (alqotel) 
13225118ebe8SLucas Mateus Castro (alqotel)     ret = get_physical_address_wtlb(env, &ctx, eaddr, access_type,
13235118ebe8SLucas Mateus Castro (alqotel)                                     type, mmu_idx);
13245118ebe8SLucas Mateus Castro (alqotel)     if (ret == 0) {
13255118ebe8SLucas Mateus Castro (alqotel)         *raddrp = ctx.raddr;
13265118ebe8SLucas Mateus Castro (alqotel)         *protp = ctx.prot;
13275118ebe8SLucas Mateus Castro (alqotel)         *psizep = TARGET_PAGE_BITS;
13285118ebe8SLucas Mateus Castro (alqotel)         return true;
13295118ebe8SLucas Mateus Castro (alqotel)     }
13305118ebe8SLucas Mateus Castro (alqotel) 
13315118ebe8SLucas Mateus Castro (alqotel)     if (guest_visible) {
133256964585SCédric Le Goater         log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
13335118ebe8SLucas Mateus Castro (alqotel)         if (type == ACCESS_CODE) {
13345118ebe8SLucas Mateus Castro (alqotel)             switch (ret) {
13355118ebe8SLucas Mateus Castro (alqotel)             case -1:
13365118ebe8SLucas Mateus Castro (alqotel)                 /* No matches in page tables or TLB */
13375118ebe8SLucas Mateus Castro (alqotel)                 switch (env->mmu_model) {
13385118ebe8SLucas Mateus Castro (alqotel)                 case POWERPC_MMU_SOFT_6xx:
13395118ebe8SLucas Mateus Castro (alqotel)                     cs->exception_index = POWERPC_EXCP_IFTLB;
13405118ebe8SLucas Mateus Castro (alqotel)                     env->error_code = 1 << 18;
13415118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_IMISS] = eaddr;
13425118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
13435118ebe8SLucas Mateus Castro (alqotel)                     goto tlb_miss;
13445118ebe8SLucas Mateus Castro (alqotel)                 case POWERPC_MMU_SOFT_4xx:
13455118ebe8SLucas Mateus Castro (alqotel)                     cs->exception_index = POWERPC_EXCP_ITLB;
13465118ebe8SLucas Mateus Castro (alqotel)                     env->error_code = 0;
13475118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_40x_DEAR] = eaddr;
13485118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_40x_ESR] = 0x00000000;
13495118ebe8SLucas Mateus Castro (alqotel)                     break;
13505118ebe8SLucas Mateus Castro (alqotel)                 case POWERPC_MMU_BOOKE206:
13515118ebe8SLucas Mateus Castro (alqotel)                     booke206_update_mas_tlb_miss(env, eaddr, 2, mmu_idx);
13525118ebe8SLucas Mateus Castro (alqotel)                     /* fall through */
13535118ebe8SLucas Mateus Castro (alqotel)                 case POWERPC_MMU_BOOKE:
13545118ebe8SLucas Mateus Castro (alqotel)                     cs->exception_index = POWERPC_EXCP_ITLB;
13555118ebe8SLucas Mateus Castro (alqotel)                     env->error_code = 0;
13565118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_BOOKE_DEAR] = eaddr;
13575118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, MMU_DATA_LOAD);
13585118ebe8SLucas Mateus Castro (alqotel)                     break;
13595118ebe8SLucas Mateus Castro (alqotel)                 case POWERPC_MMU_MPC8xx:
13605118ebe8SLucas Mateus Castro (alqotel)                     cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
13615118ebe8SLucas Mateus Castro (alqotel)                 case POWERPC_MMU_REAL:
13625118ebe8SLucas Mateus Castro (alqotel)                     cpu_abort(cs, "PowerPC in real mode should never raise "
13635118ebe8SLucas Mateus Castro (alqotel)                               "any MMU exceptions\n");
13645118ebe8SLucas Mateus Castro (alqotel)                 default:
13655118ebe8SLucas Mateus Castro (alqotel)                     cpu_abort(cs, "Unknown or invalid MMU model\n");
13665118ebe8SLucas Mateus Castro (alqotel)                 }
13675118ebe8SLucas Mateus Castro (alqotel)                 break;
13685118ebe8SLucas Mateus Castro (alqotel)             case -2:
13695118ebe8SLucas Mateus Castro (alqotel)                 /* Access rights violation */
13705118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_ISI;
1371e31ea5d8SVitaly Cheptsov                 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1372e31ea5d8SVitaly Cheptsov                     (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1373e31ea5d8SVitaly Cheptsov                     env->error_code = 0;
1374e31ea5d8SVitaly Cheptsov                 } else {
13755118ebe8SLucas Mateus Castro (alqotel)                     env->error_code = 0x08000000;
1376e31ea5d8SVitaly Cheptsov                 }
13775118ebe8SLucas Mateus Castro (alqotel)                 break;
13785118ebe8SLucas Mateus Castro (alqotel)             case -3:
13795118ebe8SLucas Mateus Castro (alqotel)                 /* No execute protection violation */
13805118ebe8SLucas Mateus Castro (alqotel)                 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
13815118ebe8SLucas Mateus Castro (alqotel)                     (env->mmu_model == POWERPC_MMU_BOOKE206)) {
13825118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_BOOKE_ESR] = 0x00000000;
1383e31ea5d8SVitaly Cheptsov                     env->error_code = 0;
1384e31ea5d8SVitaly Cheptsov                 } else {
1385e31ea5d8SVitaly Cheptsov                     env->error_code = 0x10000000;
13865118ebe8SLucas Mateus Castro (alqotel)                 }
13875118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_ISI;
13885118ebe8SLucas Mateus Castro (alqotel)                 break;
13895118ebe8SLucas Mateus Castro (alqotel)             case -4:
13905118ebe8SLucas Mateus Castro (alqotel)                 /* Direct store exception */
13915118ebe8SLucas Mateus Castro (alqotel)                 /* No code fetch is allowed in direct-store areas */
13925118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_ISI;
1393e31ea5d8SVitaly Cheptsov                 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1394e31ea5d8SVitaly Cheptsov                     (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1395e31ea5d8SVitaly Cheptsov                     env->error_code = 0;
1396e31ea5d8SVitaly Cheptsov                 } else {
13975118ebe8SLucas Mateus Castro (alqotel)                     env->error_code = 0x10000000;
1398e31ea5d8SVitaly Cheptsov                 }
13995118ebe8SLucas Mateus Castro (alqotel)                 break;
14005118ebe8SLucas Mateus Castro (alqotel)             }
14015118ebe8SLucas Mateus Castro (alqotel)         } else {
14025118ebe8SLucas Mateus Castro (alqotel)             switch (ret) {
14035118ebe8SLucas Mateus Castro (alqotel)             case -1:
14045118ebe8SLucas Mateus Castro (alqotel)                 /* No matches in page tables or TLB */
14055118ebe8SLucas Mateus Castro (alqotel)                 switch (env->mmu_model) {
14065118ebe8SLucas Mateus Castro (alqotel)                 case POWERPC_MMU_SOFT_6xx:
14075118ebe8SLucas Mateus Castro (alqotel)                     if (access_type == MMU_DATA_STORE) {
14085118ebe8SLucas Mateus Castro (alqotel)                         cs->exception_index = POWERPC_EXCP_DSTLB;
14095118ebe8SLucas Mateus Castro (alqotel)                         env->error_code = 1 << 16;
14105118ebe8SLucas Mateus Castro (alqotel)                     } else {
14115118ebe8SLucas Mateus Castro (alqotel)                         cs->exception_index = POWERPC_EXCP_DLTLB;
14125118ebe8SLucas Mateus Castro (alqotel)                         env->error_code = 0;
14135118ebe8SLucas Mateus Castro (alqotel)                     }
14145118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DMISS] = eaddr;
14155118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
14165118ebe8SLucas Mateus Castro (alqotel)                 tlb_miss:
14175118ebe8SLucas Mateus Castro (alqotel)                     env->error_code |= ctx.key << 19;
14185118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
14195118ebe8SLucas Mateus Castro (alqotel)                         get_pteg_offset32(cpu, ctx.hash[0]);
14205118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
14215118ebe8SLucas Mateus Castro (alqotel)                         get_pteg_offset32(cpu, ctx.hash[1]);
14225118ebe8SLucas Mateus Castro (alqotel)                     break;
14235118ebe8SLucas Mateus Castro (alqotel)                 case POWERPC_MMU_SOFT_4xx:
14245118ebe8SLucas Mateus Castro (alqotel)                     cs->exception_index = POWERPC_EXCP_DTLB;
14255118ebe8SLucas Mateus Castro (alqotel)                     env->error_code = 0;
14265118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_40x_DEAR] = eaddr;
14275118ebe8SLucas Mateus Castro (alqotel)                     if (access_type == MMU_DATA_STORE) {
14285118ebe8SLucas Mateus Castro (alqotel)                         env->spr[SPR_40x_ESR] = 0x00800000;
14295118ebe8SLucas Mateus Castro (alqotel)                     } else {
14305118ebe8SLucas Mateus Castro (alqotel)                         env->spr[SPR_40x_ESR] = 0x00000000;
14315118ebe8SLucas Mateus Castro (alqotel)                     }
14325118ebe8SLucas Mateus Castro (alqotel)                     break;
14335118ebe8SLucas Mateus Castro (alqotel)                 case POWERPC_MMU_MPC8xx:
14345118ebe8SLucas Mateus Castro (alqotel)                     /* XXX: TODO */
14355118ebe8SLucas Mateus Castro (alqotel)                     cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
14365118ebe8SLucas Mateus Castro (alqotel)                 case POWERPC_MMU_BOOKE206:
14375118ebe8SLucas Mateus Castro (alqotel)                     booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
14385118ebe8SLucas Mateus Castro (alqotel)                     /* fall through */
14395118ebe8SLucas Mateus Castro (alqotel)                 case POWERPC_MMU_BOOKE:
14405118ebe8SLucas Mateus Castro (alqotel)                     cs->exception_index = POWERPC_EXCP_DTLB;
14415118ebe8SLucas Mateus Castro (alqotel)                     env->error_code = 0;
14425118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_BOOKE_DEAR] = eaddr;
14435118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
14445118ebe8SLucas Mateus Castro (alqotel)                     break;
14455118ebe8SLucas Mateus Castro (alqotel)                 case POWERPC_MMU_REAL:
14465118ebe8SLucas Mateus Castro (alqotel)                     cpu_abort(cs, "PowerPC in real mode should never raise "
14475118ebe8SLucas Mateus Castro (alqotel)                               "any MMU exceptions\n");
14485118ebe8SLucas Mateus Castro (alqotel)                 default:
14495118ebe8SLucas Mateus Castro (alqotel)                     cpu_abort(cs, "Unknown or invalid MMU model\n");
14505118ebe8SLucas Mateus Castro (alqotel)                 }
14515118ebe8SLucas Mateus Castro (alqotel)                 break;
14525118ebe8SLucas Mateus Castro (alqotel)             case -2:
14535118ebe8SLucas Mateus Castro (alqotel)                 /* Access rights violation */
14545118ebe8SLucas Mateus Castro (alqotel)                 cs->exception_index = POWERPC_EXCP_DSI;
14555118ebe8SLucas Mateus Castro (alqotel)                 env->error_code = 0;
1456c8f49e6bSCédric Le Goater                 if (env->mmu_model == POWERPC_MMU_SOFT_4xx) {
14575118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_40x_DEAR] = eaddr;
14585118ebe8SLucas Mateus Castro (alqotel)                     if (access_type == MMU_DATA_STORE) {
14595118ebe8SLucas Mateus Castro (alqotel)                         env->spr[SPR_40x_ESR] |= 0x00800000;
14605118ebe8SLucas Mateus Castro (alqotel)                     }
14615118ebe8SLucas Mateus Castro (alqotel)                 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
14625118ebe8SLucas Mateus Castro (alqotel)                            (env->mmu_model == POWERPC_MMU_BOOKE206)) {
14635118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_BOOKE_DEAR] = eaddr;
14645118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
14655118ebe8SLucas Mateus Castro (alqotel)                 } else {
14665118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DAR] = eaddr;
14675118ebe8SLucas Mateus Castro (alqotel)                     if (access_type == MMU_DATA_STORE) {
14685118ebe8SLucas Mateus Castro (alqotel)                         env->spr[SPR_DSISR] = 0x0A000000;
14695118ebe8SLucas Mateus Castro (alqotel)                     } else {
14705118ebe8SLucas Mateus Castro (alqotel)                         env->spr[SPR_DSISR] = 0x08000000;
14715118ebe8SLucas Mateus Castro (alqotel)                     }
14725118ebe8SLucas Mateus Castro (alqotel)                 }
14735118ebe8SLucas Mateus Castro (alqotel)                 break;
14745118ebe8SLucas Mateus Castro (alqotel)             case -4:
14755118ebe8SLucas Mateus Castro (alqotel)                 /* Direct store exception */
14765118ebe8SLucas Mateus Castro (alqotel)                 switch (type) {
14775118ebe8SLucas Mateus Castro (alqotel)                 case ACCESS_FLOAT:
14785118ebe8SLucas Mateus Castro (alqotel)                     /* Floating point load/store */
14795118ebe8SLucas Mateus Castro (alqotel)                     cs->exception_index = POWERPC_EXCP_ALIGN;
14805118ebe8SLucas Mateus Castro (alqotel)                     env->error_code = POWERPC_EXCP_ALIGN_FP;
14815118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DAR] = eaddr;
14825118ebe8SLucas Mateus Castro (alqotel)                     break;
14835118ebe8SLucas Mateus Castro (alqotel)                 case ACCESS_RES:
14845118ebe8SLucas Mateus Castro (alqotel)                     /* lwarx, ldarx or stwcx. */
14855118ebe8SLucas Mateus Castro (alqotel)                     cs->exception_index = POWERPC_EXCP_DSI;
14865118ebe8SLucas Mateus Castro (alqotel)                     env->error_code = 0;
14875118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DAR] = eaddr;
14885118ebe8SLucas Mateus Castro (alqotel)                     if (access_type == MMU_DATA_STORE) {
14895118ebe8SLucas Mateus Castro (alqotel)                         env->spr[SPR_DSISR] = 0x06000000;
14905118ebe8SLucas Mateus Castro (alqotel)                     } else {
14915118ebe8SLucas Mateus Castro (alqotel)                         env->spr[SPR_DSISR] = 0x04000000;
14925118ebe8SLucas Mateus Castro (alqotel)                     }
14935118ebe8SLucas Mateus Castro (alqotel)                     break;
14945118ebe8SLucas Mateus Castro (alqotel)                 case ACCESS_EXT:
14955118ebe8SLucas Mateus Castro (alqotel)                     /* eciwx or ecowx */
14965118ebe8SLucas Mateus Castro (alqotel)                     cs->exception_index = POWERPC_EXCP_DSI;
14975118ebe8SLucas Mateus Castro (alqotel)                     env->error_code = 0;
14985118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DAR] = eaddr;
14995118ebe8SLucas Mateus Castro (alqotel)                     if (access_type == MMU_DATA_STORE) {
15005118ebe8SLucas Mateus Castro (alqotel)                         env->spr[SPR_DSISR] = 0x06100000;
15015118ebe8SLucas Mateus Castro (alqotel)                     } else {
15025118ebe8SLucas Mateus Castro (alqotel)                         env->spr[SPR_DSISR] = 0x04100000;
15035118ebe8SLucas Mateus Castro (alqotel)                     }
15045118ebe8SLucas Mateus Castro (alqotel)                     break;
15055118ebe8SLucas Mateus Castro (alqotel)                 default:
15065118ebe8SLucas Mateus Castro (alqotel)                     printf("DSI: invalid exception (%d)\n", ret);
15075118ebe8SLucas Mateus Castro (alqotel)                     cs->exception_index = POWERPC_EXCP_PROGRAM;
15085118ebe8SLucas Mateus Castro (alqotel)                     env->error_code =
15095118ebe8SLucas Mateus Castro (alqotel)                         POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
15105118ebe8SLucas Mateus Castro (alqotel)                     env->spr[SPR_DAR] = eaddr;
15115118ebe8SLucas Mateus Castro (alqotel)                     break;
15125118ebe8SLucas Mateus Castro (alqotel)                 }
15135118ebe8SLucas Mateus Castro (alqotel)                 break;
15145118ebe8SLucas Mateus Castro (alqotel)             }
15155118ebe8SLucas Mateus Castro (alqotel)         }
15165118ebe8SLucas Mateus Castro (alqotel)     }
15175118ebe8SLucas Mateus Castro (alqotel)     return false;
15185118ebe8SLucas Mateus Castro (alqotel) }
15195118ebe8SLucas Mateus Castro (alqotel) 
15205118ebe8SLucas Mateus Castro (alqotel) /*****************************************************************************/
15215118ebe8SLucas Mateus Castro (alqotel) 
15225118ebe8SLucas Mateus Castro (alqotel) bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
15235118ebe8SLucas Mateus Castro (alqotel)                       hwaddr *raddrp, int *psizep, int *protp,
15245118ebe8SLucas Mateus Castro (alqotel)                       int mmu_idx, bool guest_visible)
15255118ebe8SLucas Mateus Castro (alqotel) {
15265118ebe8SLucas Mateus Castro (alqotel)     switch (cpu->env.mmu_model) {
15275118ebe8SLucas Mateus Castro (alqotel) #if defined(TARGET_PPC64)
15285118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_3_00:
15295118ebe8SLucas Mateus Castro (alqotel)         if (ppc64_v3_radix(cpu)) {
15305118ebe8SLucas Mateus Castro (alqotel)             return ppc_radix64_xlate(cpu, eaddr, access_type, raddrp,
15315118ebe8SLucas Mateus Castro (alqotel)                                      psizep, protp, mmu_idx, guest_visible);
15325118ebe8SLucas Mateus Castro (alqotel)         }
15335118ebe8SLucas Mateus Castro (alqotel)         /* fall through */
15345118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_64B:
15355118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_03:
15365118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_06:
15375118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_2_07:
15385118ebe8SLucas Mateus Castro (alqotel)         return ppc_hash64_xlate(cpu, eaddr, access_type,
15395118ebe8SLucas Mateus Castro (alqotel)                                 raddrp, psizep, protp, mmu_idx, guest_visible);
15405118ebe8SLucas Mateus Castro (alqotel) #endif
15415118ebe8SLucas Mateus Castro (alqotel) 
15425118ebe8SLucas Mateus Castro (alqotel)     case POWERPC_MMU_32B:
15435118ebe8SLucas Mateus Castro (alqotel)         return ppc_hash32_xlate(cpu, eaddr, access_type, raddrp,
15445118ebe8SLucas Mateus Castro (alqotel)                                psizep, protp, mmu_idx, guest_visible);
15455118ebe8SLucas Mateus Castro (alqotel) 
15465118ebe8SLucas Mateus Castro (alqotel)     default:
15475118ebe8SLucas Mateus Castro (alqotel)         return ppc_jumbo_xlate(cpu, eaddr, access_type, raddrp,
15485118ebe8SLucas Mateus Castro (alqotel)                                psizep, protp, mmu_idx, guest_visible);
15495118ebe8SLucas Mateus Castro (alqotel)     }
15505118ebe8SLucas Mateus Castro (alqotel) }
15515118ebe8SLucas Mateus Castro (alqotel) 
15525118ebe8SLucas Mateus Castro (alqotel) hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
15535118ebe8SLucas Mateus Castro (alqotel) {
15545118ebe8SLucas Mateus Castro (alqotel)     PowerPCCPU *cpu = POWERPC_CPU(cs);
15555118ebe8SLucas Mateus Castro (alqotel)     hwaddr raddr;
15565118ebe8SLucas Mateus Castro (alqotel)     int s, p;
15575118ebe8SLucas Mateus Castro (alqotel) 
15585118ebe8SLucas Mateus Castro (alqotel)     /*
15595118ebe8SLucas Mateus Castro (alqotel)      * Some MMUs have separate TLBs for code and data. If we only
15605118ebe8SLucas Mateus Castro (alqotel)      * try an MMU_DATA_LOAD, we may not be able to read instructions
15615118ebe8SLucas Mateus Castro (alqotel)      * mapped by code TLBs, so we also try a MMU_INST_FETCH.
15625118ebe8SLucas Mateus Castro (alqotel)      */
15635118ebe8SLucas Mateus Castro (alqotel)     if (ppc_xlate(cpu, addr, MMU_DATA_LOAD, &raddr, &s, &p,
1564*fb00f730SRichard Henderson                   ppc_env_mmu_index(&cpu->env, false), false) ||
15655118ebe8SLucas Mateus Castro (alqotel)         ppc_xlate(cpu, addr, MMU_INST_FETCH, &raddr, &s, &p,
1566*fb00f730SRichard Henderson                   ppc_env_mmu_index(&cpu->env, true), false)) {
15675118ebe8SLucas Mateus Castro (alqotel)         return raddr & TARGET_PAGE_MASK;
15685118ebe8SLucas Mateus Castro (alqotel)     }
15695118ebe8SLucas Mateus Castro (alqotel)     return -1;
15705118ebe8SLucas Mateus Castro (alqotel) }
1571