1 /* 2 * PowerPC BookE MMU, TLB emulation helpers for QEMU. 3 * 4 * Copyright (c) 2003-2007 Jocelyn Mayer 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "qemu/osdep.h" 21 #include "exec/page-protection.h" 22 #include "exec/log.h" 23 #include "cpu.h" 24 #include "internal.h" 25 #include "mmu-booke.h" 26 27 /* Generic TLB check function for embedded PowerPC implementations */ 28 static bool ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb, 29 hwaddr *raddrp, 30 target_ulong address, uint32_t pid, int i) 31 { 32 target_ulong mask; 33 34 /* Check valid flag */ 35 if (!(tlb->prot & PAGE_VALID)) { 36 return false; 37 } 38 mask = ~(tlb->size - 1); 39 qemu_log_mask(CPU_LOG_MMU, "%s: TLB %d address " TARGET_FMT_lx 40 " PID %u <=> " TARGET_FMT_lx " " TARGET_FMT_lx " %u %x\n", 41 __func__, i, address, pid, tlb->EPN, 42 mask, (uint32_t)tlb->PID, tlb->prot); 43 /* Check PID */ 44 if (tlb->PID != 0 && tlb->PID != pid) { 45 return false; 46 } 47 /* Check effective address */ 48 if ((address & mask) != tlb->EPN) { 49 return false; 50 } 51 *raddrp = (tlb->RPN & mask) | (address & ~mask); 52 return true; 53 } 54 55 /* Generic TLB search function for PowerPC embedded implementations */ 56 int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid) 57 { 58 ppcemb_tlb_t *tlb; 59 hwaddr raddr; 60 int i; 61 62 for (i = 0; i < env->nb_tlb; i++) { 63 tlb = &env->tlb.tlbe[i]; 64 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, i)) { 65 return i; 66 } 67 } 68 return -1; 69 } 70 71 int mmu40x_get_physical_address(CPUPPCState *env, hwaddr *raddr, int *prot, 72 target_ulong address, 73 MMUAccessType access_type) 74 { 75 ppcemb_tlb_t *tlb; 76 int i, ret, zsel, zpr, pr; 77 78 ret = -1; 79 pr = FIELD_EX64(env->msr, MSR, PR); 80 for (i = 0; i < env->nb_tlb; i++) { 81 tlb = &env->tlb.tlbe[i]; 82 if (!ppcemb_tlb_check(env, tlb, raddr, address, 83 env->spr[SPR_40x_PID], i)) { 84 continue; 85 } 86 zsel = (tlb->attr >> 4) & 0xF; 87 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3; 88 qemu_log_mask(CPU_LOG_MMU, 89 "%s: TLB %d zsel %d zpr %d ty %d attr %08x\n", 90 __func__, i, zsel, zpr, access_type, tlb->attr); 91 /* Check execute enable bit */ 92 switch (zpr) { 93 case 0x2: 94 if (pr != 0) { 95 goto check_perms; 96 } 97 /* fall through */ 98 case 0x3: 99 /* All accesses granted */ 100 *prot = PAGE_RWX; 101 ret = 0; 102 break; 103 104 case 0x0: 105 if (pr != 0) { 106 /* Raise Zone protection fault. */ 107 env->spr[SPR_40x_ESR] = 1 << 22; 108 *prot = 0; 109 ret = -2; 110 break; 111 } 112 /* fall through */ 113 case 0x1: 114 check_perms: 115 /* Check from TLB entry */ 116 *prot = tlb->prot; 117 if (check_prot_access_type(*prot, access_type)) { 118 ret = 0; 119 } else { 120 env->spr[SPR_40x_ESR] = 0; 121 ret = -2; 122 } 123 break; 124 } 125 } 126 qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => " 127 HWADDR_FMT_plx " %d %d\n", __func__, 128 ret < 0 ? "refused" : "granted", address, 129 ret < 0 ? 0 : *raddr, *prot, ret); 130 131 return ret; 132 } 133 134 static bool mmubooke_check_pid(CPUPPCState *env, ppcemb_tlb_t *tlb, 135 hwaddr *raddr, target_ulong addr, int i) 136 { 137 if (ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID], i)) { 138 if (!env->nb_pids) { 139 /* Extend the physical address to 36 bits */ 140 *raddr |= (uint64_t)(tlb->RPN & 0xF) << 32; 141 } 142 return true; 143 } else if (!env->nb_pids) { 144 return false; 145 } 146 if (env->spr[SPR_BOOKE_PID1] && 147 ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID1], i)) { 148 return true; 149 } 150 if (env->spr[SPR_BOOKE_PID2] && 151 ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID2], i)) { 152 return true; 153 } 154 return false; 155 } 156 157 static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb, 158 hwaddr *raddr, int *prot, target_ulong address, 159 MMUAccessType access_type, int i) 160 { 161 if (!mmubooke_check_pid(env, tlb, raddr, address, i)) { 162 qemu_log_mask(CPU_LOG_MMU, "%s: TLB entry not found\n", __func__); 163 return -1; 164 } 165 166 /* Check the address space */ 167 if ((access_type == MMU_INST_FETCH ? 168 FIELD_EX64(env->msr, MSR, IR) : 169 FIELD_EX64(env->msr, MSR, DR)) != (tlb->attr & 1)) { 170 qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__); 171 return -1; 172 } 173 174 if (FIELD_EX64(env->msr, MSR, PR)) { 175 *prot = tlb->prot & 0xF; 176 } else { 177 *prot = (tlb->prot >> 4) & 0xF; 178 } 179 if (check_prot_access_type(*prot, access_type)) { 180 qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__); 181 return 0; 182 } 183 184 qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot); 185 return access_type == MMU_INST_FETCH ? -3 : -2; 186 } 187 188 static int mmubooke_get_physical_address(CPUPPCState *env, hwaddr *raddr, 189 int *prot, target_ulong address, 190 MMUAccessType access_type) 191 { 192 ppcemb_tlb_t *tlb; 193 int i, ret = -1; 194 195 for (i = 0; i < env->nb_tlb; i++) { 196 tlb = &env->tlb.tlbe[i]; 197 ret = mmubooke_check_tlb(env, tlb, raddr, prot, address, 198 access_type, i); 199 if (ret != -1) { 200 break; 201 } 202 } 203 qemu_log_mask(CPU_LOG_MMU, 204 "%s: access %s " TARGET_FMT_lx " => " HWADDR_FMT_plx 205 " %d %d\n", __func__, ret < 0 ? "refused" : "granted", 206 address, ret < 0 ? -1 : *raddr, ret == -1 ? 0 : *prot, ret); 207 return ret; 208 } 209 210 hwaddr booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb) 211 { 212 int tlbm_size; 213 214 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; 215 216 return 1024ULL << tlbm_size; 217 } 218 219 /* TLB check function for MAS based SoftTLBs */ 220 int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddrp, 221 target_ulong address, uint32_t pid) 222 { 223 hwaddr mask; 224 uint32_t tlb_pid; 225 226 if (!FIELD_EX64(env->msr, MSR, CM)) { 227 /* In 32bit mode we can only address 32bit EAs */ 228 address = (uint32_t)address; 229 } 230 231 /* Check valid flag */ 232 if (!(tlb->mas1 & MAS1_VALID)) { 233 return -1; 234 } 235 236 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); 237 qemu_log_mask(CPU_LOG_MMU, "%s: TLB ADDR=0x" TARGET_FMT_lx 238 " PID=0x%x MAS1=0x%x MAS2=0x%" PRIx64 " mask=0x%" 239 HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%" PRIx32 "\n", 240 __func__, address, pid, tlb->mas1, tlb->mas2, mask, 241 tlb->mas7_3, tlb->mas8); 242 243 /* Check PID */ 244 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT; 245 if (tlb_pid != 0 && tlb_pid != pid) { 246 return -1; 247 } 248 249 /* Check effective address */ 250 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) { 251 return -1; 252 } 253 254 if (raddrp) { 255 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask); 256 } 257 258 return 0; 259 } 260 261 static bool is_epid_mmu(int mmu_idx) 262 { 263 return mmu_idx == PPC_TLB_EPID_STORE || mmu_idx == PPC_TLB_EPID_LOAD; 264 } 265 266 static uint32_t mmubooke206_esr(int mmu_idx, MMUAccessType access_type) 267 { 268 uint32_t esr = 0; 269 if (access_type == MMU_DATA_STORE) { 270 esr |= ESR_ST; 271 } 272 if (is_epid_mmu(mmu_idx)) { 273 esr |= ESR_EPID; 274 } 275 return esr; 276 } 277 278 /* 279 * Get EPID register given the mmu_idx. If this is regular load, 280 * construct the EPID access bits from current processor state 281 * 282 * Get the effective AS and PR bits and the PID. The PID is returned 283 * only if EPID load is requested, otherwise the caller must detect 284 * the correct EPID. Return true if valid EPID is returned. 285 */ 286 static bool mmubooke206_get_as(CPUPPCState *env, 287 int mmu_idx, uint32_t *epid_out, 288 bool *as_out, bool *pr_out) 289 { 290 if (is_epid_mmu(mmu_idx)) { 291 uint32_t epidr; 292 if (mmu_idx == PPC_TLB_EPID_STORE) { 293 epidr = env->spr[SPR_BOOKE_EPSC]; 294 } else { 295 epidr = env->spr[SPR_BOOKE_EPLC]; 296 } 297 *epid_out = (epidr & EPID_EPID) >> EPID_EPID_SHIFT; 298 *as_out = !!(epidr & EPID_EAS); 299 *pr_out = !!(epidr & EPID_EPR); 300 return true; 301 } else { 302 *as_out = FIELD_EX64(env->msr, MSR, DS); 303 *pr_out = FIELD_EX64(env->msr, MSR, PR); 304 return false; 305 } 306 } 307 308 /* Check if the tlb found by hashing really matches */ 309 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb, 310 hwaddr *raddr, int *prot, 311 target_ulong address, 312 MMUAccessType access_type, int mmu_idx) 313 { 314 uint32_t epid; 315 bool as, pr; 316 bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr); 317 318 if (!use_epid) { 319 if (ppcmas_tlb_check(env, tlb, raddr, address, 320 env->spr[SPR_BOOKE_PID]) >= 0) { 321 goto found_tlb; 322 } 323 324 if (env->spr[SPR_BOOKE_PID1] && 325 ppcmas_tlb_check(env, tlb, raddr, address, 326 env->spr[SPR_BOOKE_PID1]) >= 0) { 327 goto found_tlb; 328 } 329 330 if (env->spr[SPR_BOOKE_PID2] && 331 ppcmas_tlb_check(env, tlb, raddr, address, 332 env->spr[SPR_BOOKE_PID2]) >= 0) { 333 goto found_tlb; 334 } 335 } else { 336 if (ppcmas_tlb_check(env, tlb, raddr, address, epid) >= 0) { 337 goto found_tlb; 338 } 339 } 340 341 qemu_log_mask(CPU_LOG_MMU, "%s: No TLB entry found for effective address " 342 "0x" TARGET_FMT_lx "\n", __func__, address); 343 return -1; 344 345 found_tlb: 346 347 /* Check the address space and permissions */ 348 if (access_type == MMU_INST_FETCH) { 349 /* There is no way to fetch code using epid load */ 350 assert(!use_epid); 351 as = FIELD_EX64(env->msr, MSR, IR); 352 } 353 354 if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { 355 qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__); 356 return -1; 357 } 358 359 *prot = 0; 360 if (pr) { 361 if (tlb->mas7_3 & MAS3_UR) { 362 *prot |= PAGE_READ; 363 } 364 if (tlb->mas7_3 & MAS3_UW) { 365 *prot |= PAGE_WRITE; 366 } 367 if (tlb->mas7_3 & MAS3_UX) { 368 *prot |= PAGE_EXEC; 369 } 370 } else { 371 if (tlb->mas7_3 & MAS3_SR) { 372 *prot |= PAGE_READ; 373 } 374 if (tlb->mas7_3 & MAS3_SW) { 375 *prot |= PAGE_WRITE; 376 } 377 if (tlb->mas7_3 & MAS3_SX) { 378 *prot |= PAGE_EXEC; 379 } 380 } 381 if (check_prot_access_type(*prot, access_type)) { 382 qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__); 383 return 0; 384 } 385 386 qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot); 387 return access_type == MMU_INST_FETCH ? -3 : -2; 388 } 389 390 static int mmubooke206_get_physical_address(CPUPPCState *env, hwaddr *raddr, 391 int *prot, target_ulong address, 392 MMUAccessType access_type, 393 int mmu_idx) 394 { 395 ppcmas_tlb_t *tlb; 396 int i, j, ret = -1; 397 398 for (i = 0; i < BOOKE206_MAX_TLBN; i++) { 399 int ways = booke206_tlb_ways(env, i); 400 for (j = 0; j < ways; j++) { 401 tlb = booke206_get_tlbm(env, i, address, j); 402 if (!tlb) { 403 continue; 404 } 405 ret = mmubooke206_check_tlb(env, tlb, raddr, prot, address, 406 access_type, mmu_idx); 407 if (ret != -1) { 408 goto found_tlb; 409 } 410 } 411 } 412 413 found_tlb: 414 415 qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => " 416 HWADDR_FMT_plx " %d %d\n", __func__, 417 ret < 0 ? "refused" : "granted", address, 418 ret < 0 ? -1 : *raddr, ret == -1 ? 0 : *prot, ret); 419 return ret; 420 } 421 422 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, 423 MMUAccessType access_type, int mmu_idx) 424 { 425 uint32_t epid; 426 bool as, pr; 427 uint32_t missed_tid = 0; 428 bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr); 429 430 if (access_type == MMU_INST_FETCH) { 431 as = FIELD_EX64(env->msr, MSR, IR); 432 } 433 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK; 434 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK; 435 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK; 436 env->spr[SPR_BOOKE_MAS3] = 0; 437 env->spr[SPR_BOOKE_MAS6] = 0; 438 env->spr[SPR_BOOKE_MAS7] = 0; 439 440 /* AS */ 441 if (as) { 442 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS; 443 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS; 444 } 445 446 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID; 447 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK; 448 449 if (!use_epid) { 450 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) { 451 case MAS4_TIDSELD_PID0: 452 missed_tid = env->spr[SPR_BOOKE_PID]; 453 break; 454 case MAS4_TIDSELD_PID1: 455 missed_tid = env->spr[SPR_BOOKE_PID1]; 456 break; 457 case MAS4_TIDSELD_PID2: 458 missed_tid = env->spr[SPR_BOOKE_PID2]; 459 break; 460 } 461 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16; 462 } else { 463 missed_tid = epid; 464 env->spr[SPR_BOOKE_MAS6] |= missed_tid << 16; 465 } 466 env->spr[SPR_BOOKE_MAS1] |= (missed_tid << MAS1_TID_SHIFT); 467 468 469 /* next victim logic */ 470 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT; 471 env->last_way++; 472 env->last_way &= booke206_tlb_ways(env, 0) - 1; 473 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; 474 } 475 476 bool ppc_booke_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type, 477 hwaddr *raddrp, int *psizep, int *protp, int mmu_idx, 478 bool guest_visible) 479 { 480 CPUState *cs = CPU(cpu); 481 CPUPPCState *env = &cpu->env; 482 hwaddr raddr; 483 int prot, ret; 484 485 if (env->mmu_model == POWERPC_MMU_BOOKE206) { 486 ret = mmubooke206_get_physical_address(env, &raddr, &prot, eaddr, 487 access_type, mmu_idx); 488 } else { 489 ret = mmubooke_get_physical_address(env, &raddr, &prot, eaddr, 490 access_type); 491 } 492 if (ret == 0) { 493 *raddrp = raddr; 494 *protp = prot; 495 *psizep = TARGET_PAGE_BITS; 496 return true; 497 } else if (!guest_visible) { 498 return false; 499 } 500 501 log_cpu_state_mask(CPU_LOG_MMU, cs, 0); 502 env->error_code = 0; 503 switch (ret) { 504 case -1: 505 /* No matches in page tables or TLB */ 506 if (env->mmu_model == POWERPC_MMU_BOOKE206) { 507 booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx); 508 } 509 cs->exception_index = (access_type == MMU_INST_FETCH) ? 510 POWERPC_EXCP_ITLB : POWERPC_EXCP_DTLB; 511 env->spr[SPR_BOOKE_DEAR] = eaddr; 512 env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type); 513 break; 514 case -2: 515 /* Access rights violation */ 516 cs->exception_index = (access_type == MMU_INST_FETCH) ? 517 POWERPC_EXCP_ISI : POWERPC_EXCP_DSI; 518 if (access_type != MMU_INST_FETCH) { 519 env->spr[SPR_BOOKE_DEAR] = eaddr; 520 env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type); 521 } 522 break; 523 case -3: 524 /* No execute protection violation */ 525 cs->exception_index = POWERPC_EXCP_ISI; 526 env->spr[SPR_BOOKE_ESR] = 0; 527 break; 528 } 529 530 return false; 531 } 532