1fcf5ef2aSThomas Huth /* 2fcf5ef2aSThomas Huth * PowerPC MMU, TLB and BAT emulation helpers for QEMU. 3fcf5ef2aSThomas Huth * 4fcf5ef2aSThomas Huth * Copyright (c) 2003-2007 Jocelyn Mayer 5fcf5ef2aSThomas Huth * Copyright (c) 2013 David Gibson, IBM Corporation 6fcf5ef2aSThomas Huth * 7fcf5ef2aSThomas Huth * This library is free software; you can redistribute it and/or 8fcf5ef2aSThomas Huth * modify it under the terms of the GNU Lesser General Public 9fcf5ef2aSThomas Huth * License as published by the Free Software Foundation; either 106bd039cdSChetan Pant * version 2.1 of the License, or (at your option) any later version. 11fcf5ef2aSThomas Huth * 12fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful, 13fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 14fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15fcf5ef2aSThomas Huth * Lesser General Public License for more details. 16fcf5ef2aSThomas Huth * 17fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public 18fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19fcf5ef2aSThomas Huth */ 20fcf5ef2aSThomas Huth 21fcf5ef2aSThomas Huth #include "qemu/osdep.h" 22fcf5ef2aSThomas Huth #include "cpu.h" 23fcf5ef2aSThomas Huth #include "exec/exec-all.h" 24fcf5ef2aSThomas Huth #include "sysemu/kvm.h" 25fcf5ef2aSThomas Huth #include "kvm_ppc.h" 26182357dbSRichard Henderson #include "internal.h" 27fcf5ef2aSThomas Huth #include "mmu-hash32.h" 28fcf5ef2aSThomas Huth #include "exec/log.h" 29fcf5ef2aSThomas Huth 30596e3ca8SDavid Gibson /* #define DEBUG_BAT */ 31fcf5ef2aSThomas Huth 32fcf5ef2aSThomas Huth #ifdef DEBUG_BATS 33fcf5ef2aSThomas Huth # define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__) 34fcf5ef2aSThomas Huth #else 35fcf5ef2aSThomas Huth # define LOG_BATS(...) do { } while (0) 36fcf5ef2aSThomas Huth #endif 37fcf5ef2aSThomas Huth 38fcf5ef2aSThomas Huth struct mmu_ctx_hash32 { 39fcf5ef2aSThomas Huth hwaddr raddr; /* Real address */ 40fcf5ef2aSThomas Huth int prot; /* Protection bits */ 41fcf5ef2aSThomas Huth int key; /* Access key */ 42fcf5ef2aSThomas Huth }; 43fcf5ef2aSThomas Huth 44fcf5ef2aSThomas Huth static int ppc_hash32_pp_prot(int key, int pp, int nx) 45fcf5ef2aSThomas Huth { 46fcf5ef2aSThomas Huth int prot; 47fcf5ef2aSThomas Huth 48fcf5ef2aSThomas Huth if (key == 0) { 49fcf5ef2aSThomas Huth switch (pp) { 50fcf5ef2aSThomas Huth case 0x0: 51fcf5ef2aSThomas Huth case 0x1: 52fcf5ef2aSThomas Huth case 0x2: 53fcf5ef2aSThomas Huth prot = PAGE_READ | PAGE_WRITE; 54fcf5ef2aSThomas Huth break; 55fcf5ef2aSThomas Huth 56fcf5ef2aSThomas Huth case 0x3: 57fcf5ef2aSThomas Huth prot = PAGE_READ; 58fcf5ef2aSThomas Huth break; 59fcf5ef2aSThomas Huth 60fcf5ef2aSThomas Huth default: 61fcf5ef2aSThomas Huth abort(); 62fcf5ef2aSThomas Huth } 63fcf5ef2aSThomas Huth } else { 64fcf5ef2aSThomas Huth switch (pp) { 65fcf5ef2aSThomas Huth case 0x0: 66fcf5ef2aSThomas Huth prot = 0; 67fcf5ef2aSThomas Huth break; 68fcf5ef2aSThomas Huth 69fcf5ef2aSThomas Huth case 0x1: 70fcf5ef2aSThomas Huth case 0x3: 71fcf5ef2aSThomas Huth prot = PAGE_READ; 72fcf5ef2aSThomas Huth break; 73fcf5ef2aSThomas Huth 74fcf5ef2aSThomas Huth case 0x2: 75fcf5ef2aSThomas Huth prot = PAGE_READ | PAGE_WRITE; 76fcf5ef2aSThomas Huth break; 77fcf5ef2aSThomas Huth 78fcf5ef2aSThomas Huth default: 79fcf5ef2aSThomas Huth abort(); 80fcf5ef2aSThomas Huth } 81fcf5ef2aSThomas Huth } 82fcf5ef2aSThomas Huth if (nx == 0) { 83fcf5ef2aSThomas Huth prot |= PAGE_EXEC; 84fcf5ef2aSThomas Huth } 85fcf5ef2aSThomas Huth 86fcf5ef2aSThomas Huth return prot; 87fcf5ef2aSThomas Huth } 88fcf5ef2aSThomas Huth 89fcf5ef2aSThomas Huth static int ppc_hash32_pte_prot(PowerPCCPU *cpu, 90fcf5ef2aSThomas Huth target_ulong sr, ppc_hash_pte32_t pte) 91fcf5ef2aSThomas Huth { 92fcf5ef2aSThomas Huth CPUPPCState *env = &cpu->env; 93fcf5ef2aSThomas Huth unsigned pp, key; 94fcf5ef2aSThomas Huth 95fcf5ef2aSThomas Huth key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS)); 96fcf5ef2aSThomas Huth pp = pte.pte1 & HPTE32_R_PP; 97fcf5ef2aSThomas Huth 98fcf5ef2aSThomas Huth return ppc_hash32_pp_prot(key, pp, !!(sr & SR32_NX)); 99fcf5ef2aSThomas Huth } 100fcf5ef2aSThomas Huth 101fcf5ef2aSThomas Huth static target_ulong hash32_bat_size(PowerPCCPU *cpu, 102fcf5ef2aSThomas Huth target_ulong batu, target_ulong batl) 103fcf5ef2aSThomas Huth { 104fcf5ef2aSThomas Huth CPUPPCState *env = &cpu->env; 105fcf5ef2aSThomas Huth 106fcf5ef2aSThomas Huth if ((msr_pr && !(batu & BATU32_VP)) 107fcf5ef2aSThomas Huth || (!msr_pr && !(batu & BATU32_VS))) { 108fcf5ef2aSThomas Huth return 0; 109fcf5ef2aSThomas Huth } 110fcf5ef2aSThomas Huth 111fcf5ef2aSThomas Huth return BATU32_BEPI & ~((batu & BATU32_BL) << 15); 112fcf5ef2aSThomas Huth } 113fcf5ef2aSThomas Huth 114fcf5ef2aSThomas Huth static int hash32_bat_prot(PowerPCCPU *cpu, 115fcf5ef2aSThomas Huth target_ulong batu, target_ulong batl) 116fcf5ef2aSThomas Huth { 117fcf5ef2aSThomas Huth int pp, prot; 118fcf5ef2aSThomas Huth 119fcf5ef2aSThomas Huth prot = 0; 120fcf5ef2aSThomas Huth pp = batl & BATL32_PP; 121fcf5ef2aSThomas Huth if (pp != 0) { 122fcf5ef2aSThomas Huth prot = PAGE_READ | PAGE_EXEC; 123fcf5ef2aSThomas Huth if (pp == 0x2) { 124fcf5ef2aSThomas Huth prot |= PAGE_WRITE; 125fcf5ef2aSThomas Huth } 126fcf5ef2aSThomas Huth } 127fcf5ef2aSThomas Huth return prot; 128fcf5ef2aSThomas Huth } 129fcf5ef2aSThomas Huth 130fcf5ef2aSThomas Huth static target_ulong hash32_bat_601_size(PowerPCCPU *cpu, 131fcf5ef2aSThomas Huth target_ulong batu, target_ulong batl) 132fcf5ef2aSThomas Huth { 133fcf5ef2aSThomas Huth if (!(batl & BATL32_601_V)) { 134fcf5ef2aSThomas Huth return 0; 135fcf5ef2aSThomas Huth } 136fcf5ef2aSThomas Huth 137fcf5ef2aSThomas Huth return BATU32_BEPI & ~((batl & BATL32_601_BL) << 17); 138fcf5ef2aSThomas Huth } 139fcf5ef2aSThomas Huth 140fcf5ef2aSThomas Huth static int hash32_bat_601_prot(PowerPCCPU *cpu, 141fcf5ef2aSThomas Huth target_ulong batu, target_ulong batl) 142fcf5ef2aSThomas Huth { 143fcf5ef2aSThomas Huth CPUPPCState *env = &cpu->env; 144fcf5ef2aSThomas Huth int key, pp; 145fcf5ef2aSThomas Huth 146fcf5ef2aSThomas Huth pp = batu & BATU32_601_PP; 147fcf5ef2aSThomas Huth if (msr_pr == 0) { 148fcf5ef2aSThomas Huth key = !!(batu & BATU32_601_KS); 149fcf5ef2aSThomas Huth } else { 150fcf5ef2aSThomas Huth key = !!(batu & BATU32_601_KP); 151fcf5ef2aSThomas Huth } 152fcf5ef2aSThomas Huth return ppc_hash32_pp_prot(key, pp, 0); 153fcf5ef2aSThomas Huth } 154fcf5ef2aSThomas Huth 15531fa64ecSRichard Henderson static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea, 15631fa64ecSRichard Henderson MMUAccessType access_type, int *prot) 157fcf5ef2aSThomas Huth { 158fcf5ef2aSThomas Huth CPUPPCState *env = &cpu->env; 159fcf5ef2aSThomas Huth target_ulong *BATlt, *BATut; 16031fa64ecSRichard Henderson bool ifetch = access_type == MMU_INST_FETCH; 161fcf5ef2aSThomas Huth int i; 162fcf5ef2aSThomas Huth 163fcf5ef2aSThomas Huth LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__, 16431fa64ecSRichard Henderson ifetch ? 'I' : 'D', ea); 16531fa64ecSRichard Henderson if (ifetch) { 166fcf5ef2aSThomas Huth BATlt = env->IBAT[1]; 167fcf5ef2aSThomas Huth BATut = env->IBAT[0]; 168fcf5ef2aSThomas Huth } else { 169fcf5ef2aSThomas Huth BATlt = env->DBAT[1]; 170fcf5ef2aSThomas Huth BATut = env->DBAT[0]; 171fcf5ef2aSThomas Huth } 172fcf5ef2aSThomas Huth for (i = 0; i < env->nb_BATs; i++) { 173fcf5ef2aSThomas Huth target_ulong batu = BATut[i]; 174fcf5ef2aSThomas Huth target_ulong batl = BATlt[i]; 175fcf5ef2aSThomas Huth target_ulong mask; 176fcf5ef2aSThomas Huth 177fcf5ef2aSThomas Huth if (unlikely(env->mmu_model == POWERPC_MMU_601)) { 178fcf5ef2aSThomas Huth mask = hash32_bat_601_size(cpu, batu, batl); 179fcf5ef2aSThomas Huth } else { 180fcf5ef2aSThomas Huth mask = hash32_bat_size(cpu, batu, batl); 181fcf5ef2aSThomas Huth } 182fcf5ef2aSThomas Huth LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx 183fcf5ef2aSThomas Huth " BATl " TARGET_FMT_lx "\n", __func__, 18431fa64ecSRichard Henderson ifetch ? 'I' : 'D', i, ea, batu, batl); 185fcf5ef2aSThomas Huth 186fcf5ef2aSThomas Huth if (mask && ((ea & mask) == (batu & BATU32_BEPI))) { 187fcf5ef2aSThomas Huth hwaddr raddr = (batl & mask) | (ea & ~mask); 188fcf5ef2aSThomas Huth 189fcf5ef2aSThomas Huth if (unlikely(env->mmu_model == POWERPC_MMU_601)) { 190fcf5ef2aSThomas Huth *prot = hash32_bat_601_prot(cpu, batu, batl); 191fcf5ef2aSThomas Huth } else { 192fcf5ef2aSThomas Huth *prot = hash32_bat_prot(cpu, batu, batl); 193fcf5ef2aSThomas Huth } 194fcf5ef2aSThomas Huth 195fcf5ef2aSThomas Huth return raddr & TARGET_PAGE_MASK; 196fcf5ef2aSThomas Huth } 197fcf5ef2aSThomas Huth } 198fcf5ef2aSThomas Huth 199fcf5ef2aSThomas Huth /* No hit */ 200fcf5ef2aSThomas Huth #if defined(DEBUG_BATS) 201fcf5ef2aSThomas Huth if (qemu_log_enabled()) { 202fcf5ef2aSThomas Huth LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea); 203fcf5ef2aSThomas Huth for (i = 0; i < 4; i++) { 204fcf5ef2aSThomas Huth BATu = &BATut[i]; 205fcf5ef2aSThomas Huth BATl = &BATlt[i]; 206fcf5ef2aSThomas Huth BEPIu = *BATu & BATU32_BEPIU; 207fcf5ef2aSThomas Huth BEPIl = *BATu & BATU32_BEPIL; 208fcf5ef2aSThomas Huth bl = (*BATu & 0x00001FFC) << 15; 209fcf5ef2aSThomas Huth LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx 210fcf5ef2aSThomas Huth " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " " 211fcf5ef2aSThomas Huth TARGET_FMT_lx " " TARGET_FMT_lx "\n", 21231fa64ecSRichard Henderson __func__, ifetch ? 'I' : 'D', i, ea, 213fcf5ef2aSThomas Huth *BATu, *BATl, BEPIu, BEPIl, bl); 214fcf5ef2aSThomas Huth } 215fcf5ef2aSThomas Huth } 216fcf5ef2aSThomas Huth #endif 217fcf5ef2aSThomas Huth 218fcf5ef2aSThomas Huth return -1; 219fcf5ef2aSThomas Huth } 220fcf5ef2aSThomas Huth 2216c3c873cSRichard Henderson static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr, 22231fa64ecSRichard Henderson target_ulong eaddr, 22331fa64ecSRichard Henderson MMUAccessType access_type, 2246c3c873cSRichard Henderson hwaddr *raddr, int *prot, 2256c3c873cSRichard Henderson bool guest_visible) 226fcf5ef2aSThomas Huth { 227fcf5ef2aSThomas Huth CPUState *cs = CPU(cpu); 228fcf5ef2aSThomas Huth CPUPPCState *env = &cpu->env; 229fcf5ef2aSThomas Huth int key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS)); 230fcf5ef2aSThomas Huth 231fcf5ef2aSThomas Huth qemu_log_mask(CPU_LOG_MMU, "direct store...\n"); 232fcf5ef2aSThomas Huth 233fcf5ef2aSThomas Huth if ((sr & 0x1FF00000) >> 20 == 0x07f) { 234596e3ca8SDavid Gibson /* 235596e3ca8SDavid Gibson * Memory-forced I/O controller interface access 236596e3ca8SDavid Gibson * 237596e3ca8SDavid Gibson * If T=1 and BUID=x'07F', the 601 performs a memory access 238fcf5ef2aSThomas Huth * to SR[28-31] LA[4-31], bypassing all protection mechanisms. 239fcf5ef2aSThomas Huth */ 240fcf5ef2aSThomas Huth *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF); 241fcf5ef2aSThomas Huth *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 2426c3c873cSRichard Henderson return true; 243fcf5ef2aSThomas Huth } 244fcf5ef2aSThomas Huth 24531fa64ecSRichard Henderson if (access_type == MMU_INST_FETCH) { 246fcf5ef2aSThomas Huth /* No code fetch is allowed in direct-store areas */ 2476c3c873cSRichard Henderson if (guest_visible) { 248fcf5ef2aSThomas Huth cs->exception_index = POWERPC_EXCP_ISI; 249fcf5ef2aSThomas Huth env->error_code = 0x10000000; 2506c3c873cSRichard Henderson } 2516c3c873cSRichard Henderson return false; 252fcf5ef2aSThomas Huth } 253fcf5ef2aSThomas Huth 2546c3c873cSRichard Henderson /* 2556c3c873cSRichard Henderson * From ppc_cpu_get_phys_page_debug, env->access_type is not set. 2566c3c873cSRichard Henderson * Assume ACCESS_INT for that case. 2576c3c873cSRichard Henderson */ 2586c3c873cSRichard Henderson switch (guest_visible ? env->access_type : ACCESS_INT) { 259fcf5ef2aSThomas Huth case ACCESS_INT: 260fcf5ef2aSThomas Huth /* Integer load/store : only access allowed */ 261fcf5ef2aSThomas Huth break; 262fcf5ef2aSThomas Huth case ACCESS_FLOAT: 263fcf5ef2aSThomas Huth /* Floating point load/store */ 264fcf5ef2aSThomas Huth cs->exception_index = POWERPC_EXCP_ALIGN; 265fcf5ef2aSThomas Huth env->error_code = POWERPC_EXCP_ALIGN_FP; 266fcf5ef2aSThomas Huth env->spr[SPR_DAR] = eaddr; 2676c3c873cSRichard Henderson return false; 268fcf5ef2aSThomas Huth case ACCESS_RES: 269fcf5ef2aSThomas Huth /* lwarx, ldarx or srwcx. */ 270fcf5ef2aSThomas Huth env->error_code = 0; 271fcf5ef2aSThomas Huth env->spr[SPR_DAR] = eaddr; 27231fa64ecSRichard Henderson if (access_type == MMU_DATA_STORE) { 273fcf5ef2aSThomas Huth env->spr[SPR_DSISR] = 0x06000000; 274fcf5ef2aSThomas Huth } else { 275fcf5ef2aSThomas Huth env->spr[SPR_DSISR] = 0x04000000; 276fcf5ef2aSThomas Huth } 2776c3c873cSRichard Henderson return false; 278fcf5ef2aSThomas Huth case ACCESS_CACHE: 279596e3ca8SDavid Gibson /* 280596e3ca8SDavid Gibson * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi 281596e3ca8SDavid Gibson * 282596e3ca8SDavid Gibson * Should make the instruction do no-op. As it already do 283596e3ca8SDavid Gibson * no-op, it's quite easy :-) 284fcf5ef2aSThomas Huth */ 285fcf5ef2aSThomas Huth *raddr = eaddr; 2866c3c873cSRichard Henderson return true; 287fcf5ef2aSThomas Huth case ACCESS_EXT: 288fcf5ef2aSThomas Huth /* eciwx or ecowx */ 289fcf5ef2aSThomas Huth cs->exception_index = POWERPC_EXCP_DSI; 290fcf5ef2aSThomas Huth env->error_code = 0; 291fcf5ef2aSThomas Huth env->spr[SPR_DAR] = eaddr; 29231fa64ecSRichard Henderson if (access_type == MMU_DATA_STORE) { 293fcf5ef2aSThomas Huth env->spr[SPR_DSISR] = 0x06100000; 294fcf5ef2aSThomas Huth } else { 295fcf5ef2aSThomas Huth env->spr[SPR_DSISR] = 0x04100000; 296fcf5ef2aSThomas Huth } 2976c3c873cSRichard Henderson return false; 298fcf5ef2aSThomas Huth default: 2996c3c873cSRichard Henderson cpu_abort(cs, "ERROR: insn should not need address translation\n"); 300fcf5ef2aSThomas Huth } 3016c3c873cSRichard Henderson 3026c3c873cSRichard Henderson *prot = key ? PAGE_READ | PAGE_WRITE : PAGE_READ; 3036c3c873cSRichard Henderson if (*prot & prot_for_access_type(access_type)) { 304fcf5ef2aSThomas Huth *raddr = eaddr; 3056c3c873cSRichard Henderson return true; 3066c3c873cSRichard Henderson } 3076c3c873cSRichard Henderson 3086c3c873cSRichard Henderson if (guest_visible) { 309fcf5ef2aSThomas Huth cs->exception_index = POWERPC_EXCP_DSI; 310fcf5ef2aSThomas Huth env->error_code = 0; 311fcf5ef2aSThomas Huth env->spr[SPR_DAR] = eaddr; 31231fa64ecSRichard Henderson if (access_type == MMU_DATA_STORE) { 313fcf5ef2aSThomas Huth env->spr[SPR_DSISR] = 0x0a000000; 314fcf5ef2aSThomas Huth } else { 315fcf5ef2aSThomas Huth env->spr[SPR_DSISR] = 0x08000000; 316fcf5ef2aSThomas Huth } 317fcf5ef2aSThomas Huth } 3186c3c873cSRichard Henderson return false; 319fcf5ef2aSThomas Huth } 320fcf5ef2aSThomas Huth 321fcf5ef2aSThomas Huth hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash) 322fcf5ef2aSThomas Huth { 32336778660SDavid Gibson target_ulong mask = ppc_hash32_hpt_mask(cpu); 324fcf5ef2aSThomas Huth 32536778660SDavid Gibson return (hash * HASH_PTEG_SIZE_32) & mask; 326fcf5ef2aSThomas Huth } 327fcf5ef2aSThomas Huth 328fcf5ef2aSThomas Huth static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off, 329fcf5ef2aSThomas Huth bool secondary, target_ulong ptem, 330fcf5ef2aSThomas Huth ppc_hash_pte32_t *pte) 331fcf5ef2aSThomas Huth { 332fcf5ef2aSThomas Huth hwaddr pte_offset = pteg_off; 333fcf5ef2aSThomas Huth target_ulong pte0, pte1; 334fcf5ef2aSThomas Huth int i; 335fcf5ef2aSThomas Huth 336fcf5ef2aSThomas Huth for (i = 0; i < HPTES_PER_GROUP; i++) { 337fcf5ef2aSThomas Huth pte0 = ppc_hash32_load_hpte0(cpu, pte_offset); 3383054b0caSBenjamin Herrenschmidt /* 3393054b0caSBenjamin Herrenschmidt * pte0 contains the valid bit and must be read before pte1, 3403054b0caSBenjamin Herrenschmidt * otherwise we might see an old pte1 with a new valid bit and 3413054b0caSBenjamin Herrenschmidt * thus an inconsistent hpte value 3423054b0caSBenjamin Herrenschmidt */ 3433054b0caSBenjamin Herrenschmidt smp_rmb(); 344fcf5ef2aSThomas Huth pte1 = ppc_hash32_load_hpte1(cpu, pte_offset); 345fcf5ef2aSThomas Huth 346fcf5ef2aSThomas Huth if ((pte0 & HPTE32_V_VALID) 347fcf5ef2aSThomas Huth && (secondary == !!(pte0 & HPTE32_V_SECONDARY)) 348fcf5ef2aSThomas Huth && HPTE32_V_COMPARE(pte0, ptem)) { 349fcf5ef2aSThomas Huth pte->pte0 = pte0; 350fcf5ef2aSThomas Huth pte->pte1 = pte1; 351fcf5ef2aSThomas Huth return pte_offset; 352fcf5ef2aSThomas Huth } 353fcf5ef2aSThomas Huth 354fcf5ef2aSThomas Huth pte_offset += HASH_PTE_SIZE_32; 355fcf5ef2aSThomas Huth } 356fcf5ef2aSThomas Huth 357fcf5ef2aSThomas Huth return -1; 358fcf5ef2aSThomas Huth } 359fcf5ef2aSThomas Huth 3606e8a65abSBenjamin Herrenschmidt static void ppc_hash32_set_r(PowerPCCPU *cpu, hwaddr pte_offset, uint32_t pte1) 3616e8a65abSBenjamin Herrenschmidt { 3626e8a65abSBenjamin Herrenschmidt target_ulong base = ppc_hash32_hpt_base(cpu); 3636e8a65abSBenjamin Herrenschmidt hwaddr offset = pte_offset + 6; 3646e8a65abSBenjamin Herrenschmidt 3656e8a65abSBenjamin Herrenschmidt /* The HW performs a non-atomic byte update */ 3666e8a65abSBenjamin Herrenschmidt stb_phys(CPU(cpu)->as, base + offset, ((pte1 >> 8) & 0xff) | 0x01); 3676e8a65abSBenjamin Herrenschmidt } 3686e8a65abSBenjamin Herrenschmidt 3696e8a65abSBenjamin Herrenschmidt static void ppc_hash32_set_c(PowerPCCPU *cpu, hwaddr pte_offset, uint64_t pte1) 3706e8a65abSBenjamin Herrenschmidt { 3716e8a65abSBenjamin Herrenschmidt target_ulong base = ppc_hash32_hpt_base(cpu); 3726e8a65abSBenjamin Herrenschmidt hwaddr offset = pte_offset + 7; 3736e8a65abSBenjamin Herrenschmidt 3746e8a65abSBenjamin Herrenschmidt /* The HW performs a non-atomic byte update */ 3756e8a65abSBenjamin Herrenschmidt stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80); 3766e8a65abSBenjamin Herrenschmidt } 3776e8a65abSBenjamin Herrenschmidt 378fcf5ef2aSThomas Huth static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu, 379fcf5ef2aSThomas Huth target_ulong sr, target_ulong eaddr, 380fcf5ef2aSThomas Huth ppc_hash_pte32_t *pte) 381fcf5ef2aSThomas Huth { 382fcf5ef2aSThomas Huth hwaddr pteg_off, pte_offset; 383fcf5ef2aSThomas Huth hwaddr hash; 384fcf5ef2aSThomas Huth uint32_t vsid, pgidx, ptem; 385fcf5ef2aSThomas Huth 386fcf5ef2aSThomas Huth vsid = sr & SR32_VSID; 387fcf5ef2aSThomas Huth pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS; 388fcf5ef2aSThomas Huth hash = vsid ^ pgidx; 389fcf5ef2aSThomas Huth ptem = (vsid << 7) | (pgidx >> 10); 390fcf5ef2aSThomas Huth 391fcf5ef2aSThomas Huth /* Page address translation */ 392fcf5ef2aSThomas Huth qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx 393fcf5ef2aSThomas Huth " htab_mask " TARGET_FMT_plx 394fcf5ef2aSThomas Huth " hash " TARGET_FMT_plx "\n", 39536778660SDavid Gibson ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash); 396fcf5ef2aSThomas Huth 397fcf5ef2aSThomas Huth /* Primary PTEG lookup */ 398fcf5ef2aSThomas Huth qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx 399fcf5ef2aSThomas Huth " vsid=%" PRIx32 " ptem=%" PRIx32 400fcf5ef2aSThomas Huth " hash=" TARGET_FMT_plx "\n", 40136778660SDavid Gibson ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), 40236778660SDavid Gibson vsid, ptem, hash); 403fcf5ef2aSThomas Huth pteg_off = get_pteg_offset32(cpu, hash); 404fcf5ef2aSThomas Huth pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte); 405fcf5ef2aSThomas Huth if (pte_offset == -1) { 406fcf5ef2aSThomas Huth /* Secondary PTEG lookup */ 407fcf5ef2aSThomas Huth qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx 408fcf5ef2aSThomas Huth " vsid=%" PRIx32 " api=%" PRIx32 40936778660SDavid Gibson " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu), 41036778660SDavid Gibson ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash); 411fcf5ef2aSThomas Huth pteg_off = get_pteg_offset32(cpu, ~hash); 412fcf5ef2aSThomas Huth pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte); 413fcf5ef2aSThomas Huth } 414fcf5ef2aSThomas Huth 415fcf5ef2aSThomas Huth return pte_offset; 416fcf5ef2aSThomas Huth } 417fcf5ef2aSThomas Huth 418fcf5ef2aSThomas Huth static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte, 419fcf5ef2aSThomas Huth target_ulong eaddr) 420fcf5ef2aSThomas Huth { 421fcf5ef2aSThomas Huth hwaddr rpn = pte.pte1 & HPTE32_R_RPN; 422fcf5ef2aSThomas Huth hwaddr mask = ~TARGET_PAGE_MASK; 423fcf5ef2aSThomas Huth 424fcf5ef2aSThomas Huth return (rpn & ~mask) | (eaddr & mask); 425fcf5ef2aSThomas Huth } 426fcf5ef2aSThomas Huth 427*51806b54SRichard Henderson bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type, 4286c3c873cSRichard Henderson hwaddr *raddrp, int *psizep, int *protp, 4296c3c873cSRichard Henderson bool guest_visible) 430fcf5ef2aSThomas Huth { 431fcf5ef2aSThomas Huth CPUState *cs = CPU(cpu); 432fcf5ef2aSThomas Huth CPUPPCState *env = &cpu->env; 433fcf5ef2aSThomas Huth target_ulong sr; 434fcf5ef2aSThomas Huth hwaddr pte_offset; 435fcf5ef2aSThomas Huth ppc_hash_pte32_t pte; 436fcf5ef2aSThomas Huth int prot; 437182357dbSRichard Henderson int need_prot; 438fcf5ef2aSThomas Huth hwaddr raddr; 439fcf5ef2aSThomas Huth 4406c3c873cSRichard Henderson /* There are no hash32 large pages. */ 4416c3c873cSRichard Henderson *psizep = TARGET_PAGE_BITS; 442fcf5ef2aSThomas Huth 443fcf5ef2aSThomas Huth /* 1. Handle real mode accesses */ 44431fa64ecSRichard Henderson if (access_type == MMU_INST_FETCH ? !msr_ir : !msr_dr) { 445fcf5ef2aSThomas Huth /* Translation is off */ 4466c3c873cSRichard Henderson *raddrp = eaddr; 4476c3c873cSRichard Henderson *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 4486c3c873cSRichard Henderson return true; 449fcf5ef2aSThomas Huth } 450fcf5ef2aSThomas Huth 4516c3c873cSRichard Henderson need_prot = prot_for_access_type(access_type); 4526c3c873cSRichard Henderson 453fcf5ef2aSThomas Huth /* 2. Check Block Address Translation entries (BATs) */ 454fcf5ef2aSThomas Huth if (env->nb_BATs != 0) { 4556c3c873cSRichard Henderson raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp); 456fcf5ef2aSThomas Huth if (raddr != -1) { 4576c3c873cSRichard Henderson if (need_prot & ~*protp) { 4586c3c873cSRichard Henderson if (guest_visible) { 45931fa64ecSRichard Henderson if (access_type == MMU_INST_FETCH) { 460fcf5ef2aSThomas Huth cs->exception_index = POWERPC_EXCP_ISI; 461fcf5ef2aSThomas Huth env->error_code = 0x08000000; 462fcf5ef2aSThomas Huth } else { 463fcf5ef2aSThomas Huth cs->exception_index = POWERPC_EXCP_DSI; 464fcf5ef2aSThomas Huth env->error_code = 0; 465fcf5ef2aSThomas Huth env->spr[SPR_DAR] = eaddr; 46631fa64ecSRichard Henderson if (access_type == MMU_DATA_STORE) { 467fcf5ef2aSThomas Huth env->spr[SPR_DSISR] = 0x0a000000; 468fcf5ef2aSThomas Huth } else { 469fcf5ef2aSThomas Huth env->spr[SPR_DSISR] = 0x08000000; 470fcf5ef2aSThomas Huth } 471fcf5ef2aSThomas Huth } 472fcf5ef2aSThomas Huth } 4736c3c873cSRichard Henderson return false; 4746c3c873cSRichard Henderson } 4756c3c873cSRichard Henderson *raddrp = raddr; 4766c3c873cSRichard Henderson return true; 477fcf5ef2aSThomas Huth } 478fcf5ef2aSThomas Huth } 479fcf5ef2aSThomas Huth 480fcf5ef2aSThomas Huth /* 3. Look up the Segment Register */ 481fcf5ef2aSThomas Huth sr = env->sr[eaddr >> 28]; 482fcf5ef2aSThomas Huth 483fcf5ef2aSThomas Huth /* 4. Handle direct store segments */ 484fcf5ef2aSThomas Huth if (sr & SR32_T) { 4856c3c873cSRichard Henderson return ppc_hash32_direct_store(cpu, sr, eaddr, access_type, 4866c3c873cSRichard Henderson raddrp, protp, guest_visible); 487fcf5ef2aSThomas Huth } 488fcf5ef2aSThomas Huth 489fcf5ef2aSThomas Huth /* 5. Check for segment level no-execute violation */ 49031fa64ecSRichard Henderson if (access_type == MMU_INST_FETCH && (sr & SR32_NX)) { 4916c3c873cSRichard Henderson if (guest_visible) { 492fcf5ef2aSThomas Huth cs->exception_index = POWERPC_EXCP_ISI; 493fcf5ef2aSThomas Huth env->error_code = 0x10000000; 4946c3c873cSRichard Henderson } 4956c3c873cSRichard Henderson return false; 496fcf5ef2aSThomas Huth } 497fcf5ef2aSThomas Huth 498fcf5ef2aSThomas Huth /* 6. Locate the PTE in the hash table */ 499fcf5ef2aSThomas Huth pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte); 500fcf5ef2aSThomas Huth if (pte_offset == -1) { 5016c3c873cSRichard Henderson if (guest_visible) { 50231fa64ecSRichard Henderson if (access_type == MMU_INST_FETCH) { 503fcf5ef2aSThomas Huth cs->exception_index = POWERPC_EXCP_ISI; 504fcf5ef2aSThomas Huth env->error_code = 0x40000000; 505fcf5ef2aSThomas Huth } else { 506fcf5ef2aSThomas Huth cs->exception_index = POWERPC_EXCP_DSI; 507fcf5ef2aSThomas Huth env->error_code = 0; 508fcf5ef2aSThomas Huth env->spr[SPR_DAR] = eaddr; 50931fa64ecSRichard Henderson if (access_type == MMU_DATA_STORE) { 510fcf5ef2aSThomas Huth env->spr[SPR_DSISR] = 0x42000000; 511fcf5ef2aSThomas Huth } else { 512fcf5ef2aSThomas Huth env->spr[SPR_DSISR] = 0x40000000; 513fcf5ef2aSThomas Huth } 514fcf5ef2aSThomas Huth } 5156c3c873cSRichard Henderson } 5166c3c873cSRichard Henderson return false; 517fcf5ef2aSThomas Huth } 518fcf5ef2aSThomas Huth qemu_log_mask(CPU_LOG_MMU, 519fcf5ef2aSThomas Huth "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset); 520fcf5ef2aSThomas Huth 521fcf5ef2aSThomas Huth /* 7. Check access permissions */ 522fcf5ef2aSThomas Huth 523fcf5ef2aSThomas Huth prot = ppc_hash32_pte_prot(cpu, sr, pte); 524fcf5ef2aSThomas Huth 525182357dbSRichard Henderson if (need_prot & ~prot) { 526fcf5ef2aSThomas Huth /* Access right violation */ 527fcf5ef2aSThomas Huth qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); 5286c3c873cSRichard Henderson if (guest_visible) { 52931fa64ecSRichard Henderson if (access_type == MMU_INST_FETCH) { 530fcf5ef2aSThomas Huth cs->exception_index = POWERPC_EXCP_ISI; 531fcf5ef2aSThomas Huth env->error_code = 0x08000000; 532fcf5ef2aSThomas Huth } else { 533fcf5ef2aSThomas Huth cs->exception_index = POWERPC_EXCP_DSI; 534fcf5ef2aSThomas Huth env->error_code = 0; 535fcf5ef2aSThomas Huth env->spr[SPR_DAR] = eaddr; 53631fa64ecSRichard Henderson if (access_type == MMU_DATA_STORE) { 537fcf5ef2aSThomas Huth env->spr[SPR_DSISR] = 0x0a000000; 538fcf5ef2aSThomas Huth } else { 539fcf5ef2aSThomas Huth env->spr[SPR_DSISR] = 0x08000000; 540fcf5ef2aSThomas Huth } 541fcf5ef2aSThomas Huth } 5426c3c873cSRichard Henderson } 5436c3c873cSRichard Henderson return false; 544fcf5ef2aSThomas Huth } 545fcf5ef2aSThomas Huth 546fcf5ef2aSThomas Huth qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n"); 547fcf5ef2aSThomas Huth 548fcf5ef2aSThomas Huth /* 8. Update PTE referenced and changed bits if necessary */ 549fcf5ef2aSThomas Huth 5506e8a65abSBenjamin Herrenschmidt if (!(pte.pte1 & HPTE32_R_R)) { 5516e8a65abSBenjamin Herrenschmidt ppc_hash32_set_r(cpu, pte_offset, pte.pte1); 5526e8a65abSBenjamin Herrenschmidt } 5536e8a65abSBenjamin Herrenschmidt if (!(pte.pte1 & HPTE32_R_C)) { 55431fa64ecSRichard Henderson if (access_type == MMU_DATA_STORE) { 5556e8a65abSBenjamin Herrenschmidt ppc_hash32_set_c(cpu, pte_offset, pte.pte1); 556fcf5ef2aSThomas Huth } else { 557596e3ca8SDavid Gibson /* 558596e3ca8SDavid Gibson * Treat the page as read-only for now, so that a later write 559596e3ca8SDavid Gibson * will pass through this function again to set the C bit 560596e3ca8SDavid Gibson */ 561fcf5ef2aSThomas Huth prot &= ~PAGE_WRITE; 562fcf5ef2aSThomas Huth } 563fcf5ef2aSThomas Huth } 564fcf5ef2aSThomas Huth 565fcf5ef2aSThomas Huth /* 9. Determine the real address from the PTE */ 566fcf5ef2aSThomas Huth 5676c3c873cSRichard Henderson *raddrp = ppc_hash32_pte_raddr(sr, pte, eaddr); 5686c3c873cSRichard Henderson *protp = prot; 5696c3c873cSRichard Henderson return true; 5706c3c873cSRichard Henderson } 571