1 /* 2 * PowerPC MMU, TLB, SLB and BAT 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 "qemu/units.h" 22 #include "cpu.h" 23 #include "sysemu/kvm.h" 24 #include "kvm_ppc.h" 25 #include "mmu-hash64.h" 26 #include "mmu-hash32.h" 27 #include "exec/exec-all.h" 28 #include "exec/log.h" 29 #include "helper_regs.h" 30 #include "qemu/error-report.h" 31 #include "qemu/main-loop.h" 32 #include "qemu/qemu-print.h" 33 #include "internal.h" 34 #include "mmu-book3s-v3.h" 35 #include "mmu-radix64.h" 36 #include "exec/helper-proto.h" 37 #include "exec/cpu_ldst.h" 38 39 /* #define DEBUG_BATS */ 40 /* #define DEBUG_SOFTWARE_TLB */ 41 /* #define DUMP_PAGE_TABLES */ 42 /* #define FLUSH_ALL_TLBS */ 43 44 #ifdef DEBUG_SOFTWARE_TLB 45 # define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__) 46 #else 47 # define LOG_SWTLB(...) do { } while (0) 48 #endif 49 50 #ifdef DEBUG_BATS 51 # define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__) 52 #else 53 # define LOG_BATS(...) do { } while (0) 54 #endif 55 56 /*****************************************************************************/ 57 /* PowerPC MMU emulation */ 58 59 /* Software driven TLB helpers */ 60 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env) 61 { 62 ppc6xx_tlb_t *tlb; 63 int nr, max; 64 65 /* LOG_SWTLB("Invalidate all TLBs\n"); */ 66 /* Invalidate all defined software TLB */ 67 max = env->nb_tlb; 68 if (env->id_tlbs == 1) { 69 max *= 2; 70 } 71 for (nr = 0; nr < max; nr++) { 72 tlb = &env->tlb.tlb6[nr]; 73 pte_invalidate(&tlb->pte0); 74 } 75 tlb_flush(env_cpu(env)); 76 } 77 78 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env, 79 target_ulong eaddr, 80 int is_code, int match_epn) 81 { 82 #if !defined(FLUSH_ALL_TLBS) 83 CPUState *cs = env_cpu(env); 84 ppc6xx_tlb_t *tlb; 85 int way, nr; 86 87 /* Invalidate ITLB + DTLB, all ways */ 88 for (way = 0; way < env->nb_ways; way++) { 89 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code); 90 tlb = &env->tlb.tlb6[nr]; 91 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) { 92 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr, 93 env->nb_tlb, eaddr); 94 pte_invalidate(&tlb->pte0); 95 tlb_flush_page(cs, tlb->EPN); 96 } 97 } 98 #else 99 /* XXX: PowerPC specification say this is valid as well */ 100 ppc6xx_tlb_invalidate_all(env); 101 #endif 102 } 103 104 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env, 105 target_ulong eaddr, int is_code) 106 { 107 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0); 108 } 109 110 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, 111 int is_code, target_ulong pte0, target_ulong pte1) 112 { 113 ppc6xx_tlb_t *tlb; 114 int nr; 115 116 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code); 117 tlb = &env->tlb.tlb6[nr]; 118 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx 119 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1); 120 /* Invalidate any pending reference in QEMU for this virtual address */ 121 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1); 122 tlb->pte0 = pte0; 123 tlb->pte1 = pte1; 124 tlb->EPN = EPN; 125 /* Store last way for LRU mechanism */ 126 env->last_way = way; 127 } 128 129 /* Generic TLB search function for PowerPC embedded implementations */ 130 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, 131 uint32_t pid) 132 { 133 ppcemb_tlb_t *tlb; 134 hwaddr raddr; 135 int i, ret; 136 137 /* Default return value is no match */ 138 ret = -1; 139 for (i = 0; i < env->nb_tlb; i++) { 140 tlb = &env->tlb.tlbe[i]; 141 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) { 142 ret = i; 143 break; 144 } 145 } 146 147 return ret; 148 } 149 150 /* Helpers specific to PowerPC 40x implementations */ 151 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env) 152 { 153 ppcemb_tlb_t *tlb; 154 int i; 155 156 for (i = 0; i < env->nb_tlb; i++) { 157 tlb = &env->tlb.tlbe[i]; 158 tlb->prot &= ~PAGE_VALID; 159 } 160 tlb_flush(env_cpu(env)); 161 } 162 163 static void booke206_flush_tlb(CPUPPCState *env, int flags, 164 const int check_iprot) 165 { 166 int tlb_size; 167 int i, j; 168 ppcmas_tlb_t *tlb = env->tlb.tlbm; 169 170 for (i = 0; i < BOOKE206_MAX_TLBN; i++) { 171 if (flags & (1 << i)) { 172 tlb_size = booke206_tlb_size(env, i); 173 for (j = 0; j < tlb_size; j++) { 174 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) { 175 tlb[j].mas1 &= ~MAS1_VALID; 176 } 177 } 178 } 179 tlb += booke206_tlb_size(env, i); 180 } 181 182 tlb_flush(env_cpu(env)); 183 } 184 185 static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, 186 target_ulong eaddr, MMUAccessType access_type, 187 int type) 188 { 189 return get_physical_address_wtlb(env, ctx, eaddr, access_type, type, 0); 190 } 191 192 193 194 /*****************************************************************************/ 195 /* BATs management */ 196 #if !defined(FLUSH_ALL_TLBS) 197 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu, 198 target_ulong mask) 199 { 200 CPUState *cs = env_cpu(env); 201 target_ulong base, end, page; 202 203 base = BATu & ~0x0001FFFF; 204 end = base + mask + 0x00020000; 205 if (((end - base) >> TARGET_PAGE_BITS) > 1024) { 206 /* Flushing 1024 4K pages is slower than a complete flush */ 207 LOG_BATS("Flush all BATs\n"); 208 tlb_flush(cs); 209 LOG_BATS("Flush done\n"); 210 return; 211 } 212 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " (" 213 TARGET_FMT_lx ")\n", base, end, mask); 214 for (page = base; page != end; page += TARGET_PAGE_SIZE) { 215 tlb_flush_page(cs, page); 216 } 217 LOG_BATS("Flush done\n"); 218 } 219 #endif 220 221 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr, 222 target_ulong value) 223 { 224 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID, 225 nr, ul == 0 ? 'u' : 'l', value, env->nip); 226 } 227 228 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value) 229 { 230 target_ulong mask; 231 232 dump_store_bat(env, 'I', 0, nr, value); 233 if (env->IBAT[0][nr] != value) { 234 mask = (value << 15) & 0x0FFE0000UL; 235 #if !defined(FLUSH_ALL_TLBS) 236 do_invalidate_BAT(env, env->IBAT[0][nr], mask); 237 #endif 238 /* 239 * When storing valid upper BAT, mask BEPI and BRPN and 240 * invalidate all TLBs covered by this BAT 241 */ 242 mask = (value << 15) & 0x0FFE0000UL; 243 env->IBAT[0][nr] = (value & 0x00001FFFUL) | 244 (value & ~0x0001FFFFUL & ~mask); 245 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) | 246 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask); 247 #if !defined(FLUSH_ALL_TLBS) 248 do_invalidate_BAT(env, env->IBAT[0][nr], mask); 249 #else 250 tlb_flush(env_cpu(env)); 251 #endif 252 } 253 } 254 255 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value) 256 { 257 dump_store_bat(env, 'I', 1, nr, value); 258 env->IBAT[1][nr] = value; 259 } 260 261 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value) 262 { 263 target_ulong mask; 264 265 dump_store_bat(env, 'D', 0, nr, value); 266 if (env->DBAT[0][nr] != value) { 267 /* 268 * When storing valid upper BAT, mask BEPI and BRPN and 269 * invalidate all TLBs covered by this BAT 270 */ 271 mask = (value << 15) & 0x0FFE0000UL; 272 #if !defined(FLUSH_ALL_TLBS) 273 do_invalidate_BAT(env, env->DBAT[0][nr], mask); 274 #endif 275 mask = (value << 15) & 0x0FFE0000UL; 276 env->DBAT[0][nr] = (value & 0x00001FFFUL) | 277 (value & ~0x0001FFFFUL & ~mask); 278 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) | 279 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask); 280 #if !defined(FLUSH_ALL_TLBS) 281 do_invalidate_BAT(env, env->DBAT[0][nr], mask); 282 #else 283 tlb_flush(env_cpu(env)); 284 #endif 285 } 286 } 287 288 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value) 289 { 290 dump_store_bat(env, 'D', 1, nr, value); 291 env->DBAT[1][nr] = value; 292 } 293 294 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value) 295 { 296 target_ulong mask; 297 #if defined(FLUSH_ALL_TLBS) 298 int do_inval; 299 #endif 300 301 dump_store_bat(env, 'I', 0, nr, value); 302 if (env->IBAT[0][nr] != value) { 303 #if defined(FLUSH_ALL_TLBS) 304 do_inval = 0; 305 #endif 306 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL; 307 if (env->IBAT[1][nr] & 0x40) { 308 /* Invalidate BAT only if it is valid */ 309 #if !defined(FLUSH_ALL_TLBS) 310 do_invalidate_BAT(env, env->IBAT[0][nr], mask); 311 #else 312 do_inval = 1; 313 #endif 314 } 315 /* 316 * When storing valid upper BAT, mask BEPI and BRPN and 317 * invalidate all TLBs covered by this BAT 318 */ 319 env->IBAT[0][nr] = (value & 0x00001FFFUL) | 320 (value & ~0x0001FFFFUL & ~mask); 321 env->DBAT[0][nr] = env->IBAT[0][nr]; 322 if (env->IBAT[1][nr] & 0x40) { 323 #if !defined(FLUSH_ALL_TLBS) 324 do_invalidate_BAT(env, env->IBAT[0][nr], mask); 325 #else 326 do_inval = 1; 327 #endif 328 } 329 #if defined(FLUSH_ALL_TLBS) 330 if (do_inval) { 331 tlb_flush(env_cpu(env)); 332 } 333 #endif 334 } 335 } 336 337 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value) 338 { 339 #if !defined(FLUSH_ALL_TLBS) 340 target_ulong mask; 341 #else 342 int do_inval; 343 #endif 344 345 dump_store_bat(env, 'I', 1, nr, value); 346 if (env->IBAT[1][nr] != value) { 347 #if defined(FLUSH_ALL_TLBS) 348 do_inval = 0; 349 #endif 350 if (env->IBAT[1][nr] & 0x40) { 351 #if !defined(FLUSH_ALL_TLBS) 352 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL; 353 do_invalidate_BAT(env, env->IBAT[0][nr], mask); 354 #else 355 do_inval = 1; 356 #endif 357 } 358 if (value & 0x40) { 359 #if !defined(FLUSH_ALL_TLBS) 360 mask = (value << 17) & 0x0FFE0000UL; 361 do_invalidate_BAT(env, env->IBAT[0][nr], mask); 362 #else 363 do_inval = 1; 364 #endif 365 } 366 env->IBAT[1][nr] = value; 367 env->DBAT[1][nr] = value; 368 #if defined(FLUSH_ALL_TLBS) 369 if (do_inval) { 370 tlb_flush(env_cpu(env)); 371 } 372 #endif 373 } 374 } 375 376 /*****************************************************************************/ 377 /* TLB management */ 378 void ppc_tlb_invalidate_all(CPUPPCState *env) 379 { 380 #if defined(TARGET_PPC64) 381 if (mmu_is_64bit(env->mmu_model)) { 382 env->tlb_need_flush = 0; 383 tlb_flush(env_cpu(env)); 384 } else 385 #endif /* defined(TARGET_PPC64) */ 386 switch (env->mmu_model) { 387 case POWERPC_MMU_SOFT_6xx: 388 ppc6xx_tlb_invalidate_all(env); 389 break; 390 case POWERPC_MMU_SOFT_4xx: 391 ppc4xx_tlb_invalidate_all(env); 392 break; 393 case POWERPC_MMU_REAL: 394 cpu_abort(env_cpu(env), "No TLB for PowerPC 4xx in real mode\n"); 395 break; 396 case POWERPC_MMU_MPC8xx: 397 /* XXX: TODO */ 398 cpu_abort(env_cpu(env), "MPC8xx MMU model is not implemented\n"); 399 break; 400 case POWERPC_MMU_BOOKE: 401 tlb_flush(env_cpu(env)); 402 break; 403 case POWERPC_MMU_BOOKE206: 404 booke206_flush_tlb(env, -1, 0); 405 break; 406 case POWERPC_MMU_32B: 407 case POWERPC_MMU_601: 408 env->tlb_need_flush = 0; 409 tlb_flush(env_cpu(env)); 410 break; 411 default: 412 /* XXX: TODO */ 413 cpu_abort(env_cpu(env), "Unknown MMU model %x\n", env->mmu_model); 414 break; 415 } 416 } 417 418 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) 419 { 420 #if !defined(FLUSH_ALL_TLBS) 421 addr &= TARGET_PAGE_MASK; 422 #if defined(TARGET_PPC64) 423 if (mmu_is_64bit(env->mmu_model)) { 424 /* tlbie invalidate TLBs for all segments */ 425 /* 426 * XXX: given the fact that there are too many segments to invalidate, 427 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU, 428 * we just invalidate all TLBs 429 */ 430 env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; 431 } else 432 #endif /* defined(TARGET_PPC64) */ 433 switch (env->mmu_model) { 434 case POWERPC_MMU_SOFT_6xx: 435 ppc6xx_tlb_invalidate_virt(env, addr, 0); 436 if (env->id_tlbs == 1) { 437 ppc6xx_tlb_invalidate_virt(env, addr, 1); 438 } 439 break; 440 case POWERPC_MMU_32B: 441 case POWERPC_MMU_601: 442 /* 443 * Actual CPUs invalidate entire congruence classes based on 444 * the geometry of their TLBs and some OSes take that into 445 * account, we just mark the TLB to be flushed later (context 446 * synchronizing event or sync instruction on 32-bit). 447 */ 448 env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; 449 break; 450 default: 451 /* Should never reach here with other MMU models */ 452 assert(0); 453 } 454 #else 455 ppc_tlb_invalidate_all(env); 456 #endif 457 } 458 459 /*****************************************************************************/ 460 /* Special registers manipulation */ 461 462 /* Segment registers load and store */ 463 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num) 464 { 465 #if defined(TARGET_PPC64) 466 if (mmu_is_64bit(env->mmu_model)) { 467 /* XXX */ 468 return 0; 469 } 470 #endif 471 return env->sr[sr_num]; 472 } 473 474 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value) 475 { 476 qemu_log_mask(CPU_LOG_MMU, 477 "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, 478 (int)srnum, value, env->sr[srnum]); 479 #if defined(TARGET_PPC64) 480 if (mmu_is_64bit(env->mmu_model)) { 481 PowerPCCPU *cpu = env_archcpu(env); 482 uint64_t esid, vsid; 483 484 /* ESID = srnum */ 485 esid = ((uint64_t)(srnum & 0xf) << 28) | SLB_ESID_V; 486 487 /* VSID = VSID */ 488 vsid = (value & 0xfffffff) << 12; 489 /* flags = flags */ 490 vsid |= ((value >> 27) & 0xf) << 8; 491 492 ppc_store_slb(cpu, srnum, esid, vsid); 493 } else 494 #endif 495 if (env->sr[srnum] != value) { 496 env->sr[srnum] = value; 497 /* 498 * Invalidating 256MB of virtual memory in 4kB pages is way 499 * longer than flushing the whole TLB. 500 */ 501 #if !defined(FLUSH_ALL_TLBS) && 0 502 { 503 target_ulong page, end; 504 /* Invalidate 256 MB of virtual memory */ 505 page = (16 << 20) * srnum; 506 end = page + (16 << 20); 507 for (; page != end; page += TARGET_PAGE_SIZE) { 508 tlb_flush_page(env_cpu(env), page); 509 } 510 } 511 #else 512 env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; 513 #endif 514 } 515 } 516 517 /* TLB management */ 518 void helper_tlbia(CPUPPCState *env) 519 { 520 ppc_tlb_invalidate_all(env); 521 } 522 523 void helper_tlbie(CPUPPCState *env, target_ulong addr) 524 { 525 ppc_tlb_invalidate_one(env, addr); 526 } 527 528 void helper_tlbiva(CPUPPCState *env, target_ulong addr) 529 { 530 /* tlbiva instruction only exists on BookE */ 531 assert(env->mmu_model == POWERPC_MMU_BOOKE); 532 /* XXX: TODO */ 533 cpu_abort(env_cpu(env), "BookE MMU model is not implemented\n"); 534 } 535 536 /* Software driven TLBs management */ 537 /* PowerPC 602/603 software TLB load instructions helpers */ 538 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code) 539 { 540 target_ulong RPN, CMP, EPN; 541 int way; 542 543 RPN = env->spr[SPR_RPA]; 544 if (is_code) { 545 CMP = env->spr[SPR_ICMP]; 546 EPN = env->spr[SPR_IMISS]; 547 } else { 548 CMP = env->spr[SPR_DCMP]; 549 EPN = env->spr[SPR_DMISS]; 550 } 551 way = (env->spr[SPR_SRR1] >> 17) & 1; 552 (void)EPN; /* avoid a compiler warning */ 553 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx 554 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP, 555 RPN, way); 556 /* Store this TLB */ 557 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK), 558 way, is_code, CMP, RPN); 559 } 560 561 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN) 562 { 563 do_6xx_tlb(env, EPN, 0); 564 } 565 566 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN) 567 { 568 do_6xx_tlb(env, EPN, 1); 569 } 570 571 /*****************************************************************************/ 572 /* PowerPC 601 specific instructions (POWER bridge) */ 573 574 target_ulong helper_rac(CPUPPCState *env, target_ulong addr) 575 { 576 mmu_ctx_t ctx; 577 int nb_BATs; 578 target_ulong ret = 0; 579 580 /* 581 * We don't have to generate many instances of this instruction, 582 * as rac is supervisor only. 583 * 584 * XXX: FIX THIS: Pretend we have no BAT 585 */ 586 nb_BATs = env->nb_BATs; 587 env->nb_BATs = 0; 588 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) { 589 ret = ctx.raddr; 590 } 591 env->nb_BATs = nb_BATs; 592 return ret; 593 } 594 595 static inline target_ulong booke_tlb_to_page_size(int size) 596 { 597 return 1024 << (2 * size); 598 } 599 600 static inline int booke_page_size_to_tlb(target_ulong page_size) 601 { 602 int size; 603 604 switch (page_size) { 605 case 0x00000400UL: 606 size = 0x0; 607 break; 608 case 0x00001000UL: 609 size = 0x1; 610 break; 611 case 0x00004000UL: 612 size = 0x2; 613 break; 614 case 0x00010000UL: 615 size = 0x3; 616 break; 617 case 0x00040000UL: 618 size = 0x4; 619 break; 620 case 0x00100000UL: 621 size = 0x5; 622 break; 623 case 0x00400000UL: 624 size = 0x6; 625 break; 626 case 0x01000000UL: 627 size = 0x7; 628 break; 629 case 0x04000000UL: 630 size = 0x8; 631 break; 632 case 0x10000000UL: 633 size = 0x9; 634 break; 635 case 0x40000000UL: 636 size = 0xA; 637 break; 638 #if defined(TARGET_PPC64) 639 case 0x000100000000ULL: 640 size = 0xB; 641 break; 642 case 0x000400000000ULL: 643 size = 0xC; 644 break; 645 case 0x001000000000ULL: 646 size = 0xD; 647 break; 648 case 0x004000000000ULL: 649 size = 0xE; 650 break; 651 case 0x010000000000ULL: 652 size = 0xF; 653 break; 654 #endif 655 default: 656 size = -1; 657 break; 658 } 659 660 return size; 661 } 662 663 /* Helpers for 4xx TLB management */ 664 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */ 665 666 #define PPC4XX_TLBHI_V 0x00000040 667 #define PPC4XX_TLBHI_E 0x00000020 668 #define PPC4XX_TLBHI_SIZE_MIN 0 669 #define PPC4XX_TLBHI_SIZE_MAX 7 670 #define PPC4XX_TLBHI_SIZE_DEFAULT 1 671 #define PPC4XX_TLBHI_SIZE_SHIFT 7 672 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007 673 674 #define PPC4XX_TLBLO_EX 0x00000200 675 #define PPC4XX_TLBLO_WR 0x00000100 676 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF 677 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00 678 679 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry) 680 { 681 ppcemb_tlb_t *tlb; 682 target_ulong ret; 683 int size; 684 685 entry &= PPC4XX_TLB_ENTRY_MASK; 686 tlb = &env->tlb.tlbe[entry]; 687 ret = tlb->EPN; 688 if (tlb->prot & PAGE_VALID) { 689 ret |= PPC4XX_TLBHI_V; 690 } 691 size = booke_page_size_to_tlb(tlb->size); 692 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) { 693 size = PPC4XX_TLBHI_SIZE_DEFAULT; 694 } 695 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT; 696 env->spr[SPR_40x_PID] = tlb->PID; 697 return ret; 698 } 699 700 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry) 701 { 702 ppcemb_tlb_t *tlb; 703 target_ulong ret; 704 705 entry &= PPC4XX_TLB_ENTRY_MASK; 706 tlb = &env->tlb.tlbe[entry]; 707 ret = tlb->RPN; 708 if (tlb->prot & PAGE_EXEC) { 709 ret |= PPC4XX_TLBLO_EX; 710 } 711 if (tlb->prot & PAGE_WRITE) { 712 ret |= PPC4XX_TLBLO_WR; 713 } 714 return ret; 715 } 716 717 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry, 718 target_ulong val) 719 { 720 CPUState *cs = env_cpu(env); 721 ppcemb_tlb_t *tlb; 722 target_ulong page, end; 723 724 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry, 725 val); 726 entry &= PPC4XX_TLB_ENTRY_MASK; 727 tlb = &env->tlb.tlbe[entry]; 728 /* Invalidate previous TLB (if it's valid) */ 729 if (tlb->prot & PAGE_VALID) { 730 end = tlb->EPN + tlb->size; 731 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end " 732 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end); 733 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { 734 tlb_flush_page(cs, page); 735 } 736 } 737 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT) 738 & PPC4XX_TLBHI_SIZE_MASK); 739 /* 740 * We cannot handle TLB size < TARGET_PAGE_SIZE. 741 * If this ever occurs, we should implement TARGET_PAGE_BITS_VARY 742 */ 743 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) { 744 cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u " 745 "are not supported (%d)\n" 746 "Please implement TARGET_PAGE_BITS_VARY\n", 747 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7)); 748 } 749 tlb->EPN = val & ~(tlb->size - 1); 750 if (val & PPC4XX_TLBHI_V) { 751 tlb->prot |= PAGE_VALID; 752 if (val & PPC4XX_TLBHI_E) { 753 /* XXX: TO BE FIXED */ 754 cpu_abort(cs, 755 "Little-endian TLB entries are not supported by now\n"); 756 } 757 } else { 758 tlb->prot &= ~PAGE_VALID; 759 } 760 tlb->PID = env->spr[SPR_40x_PID]; /* PID */ 761 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx 762 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__, 763 (int)entry, tlb->RPN, tlb->EPN, tlb->size, 764 tlb->prot & PAGE_READ ? 'r' : '-', 765 tlb->prot & PAGE_WRITE ? 'w' : '-', 766 tlb->prot & PAGE_EXEC ? 'x' : '-', 767 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); 768 /* Invalidate new TLB (if valid) */ 769 if (tlb->prot & PAGE_VALID) { 770 end = tlb->EPN + tlb->size; 771 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end " 772 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end); 773 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { 774 tlb_flush_page(cs, page); 775 } 776 } 777 } 778 779 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry, 780 target_ulong val) 781 { 782 ppcemb_tlb_t *tlb; 783 784 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry, 785 val); 786 entry &= PPC4XX_TLB_ENTRY_MASK; 787 tlb = &env->tlb.tlbe[entry]; 788 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK; 789 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK; 790 tlb->prot = PAGE_READ; 791 if (val & PPC4XX_TLBLO_EX) { 792 tlb->prot |= PAGE_EXEC; 793 } 794 if (val & PPC4XX_TLBLO_WR) { 795 tlb->prot |= PAGE_WRITE; 796 } 797 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx 798 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__, 799 (int)entry, tlb->RPN, tlb->EPN, tlb->size, 800 tlb->prot & PAGE_READ ? 'r' : '-', 801 tlb->prot & PAGE_WRITE ? 'w' : '-', 802 tlb->prot & PAGE_EXEC ? 'x' : '-', 803 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); 804 } 805 806 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address) 807 { 808 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]); 809 } 810 811 /* PowerPC 440 TLB management */ 812 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry, 813 target_ulong value) 814 { 815 ppcemb_tlb_t *tlb; 816 target_ulong EPN, RPN, size; 817 int do_flush_tlbs; 818 819 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n", 820 __func__, word, (int)entry, value); 821 do_flush_tlbs = 0; 822 entry &= 0x3F; 823 tlb = &env->tlb.tlbe[entry]; 824 switch (word) { 825 default: 826 /* Just here to please gcc */ 827 case 0: 828 EPN = value & 0xFFFFFC00; 829 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) { 830 do_flush_tlbs = 1; 831 } 832 tlb->EPN = EPN; 833 size = booke_tlb_to_page_size((value >> 4) & 0xF); 834 if ((tlb->prot & PAGE_VALID) && tlb->size < size) { 835 do_flush_tlbs = 1; 836 } 837 tlb->size = size; 838 tlb->attr &= ~0x1; 839 tlb->attr |= (value >> 8) & 1; 840 if (value & 0x200) { 841 tlb->prot |= PAGE_VALID; 842 } else { 843 if (tlb->prot & PAGE_VALID) { 844 tlb->prot &= ~PAGE_VALID; 845 do_flush_tlbs = 1; 846 } 847 } 848 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF; 849 if (do_flush_tlbs) { 850 tlb_flush(env_cpu(env)); 851 } 852 break; 853 case 1: 854 RPN = value & 0xFFFFFC0F; 855 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) { 856 tlb_flush(env_cpu(env)); 857 } 858 tlb->RPN = RPN; 859 break; 860 case 2: 861 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00); 862 tlb->prot = tlb->prot & PAGE_VALID; 863 if (value & 0x1) { 864 tlb->prot |= PAGE_READ << 4; 865 } 866 if (value & 0x2) { 867 tlb->prot |= PAGE_WRITE << 4; 868 } 869 if (value & 0x4) { 870 tlb->prot |= PAGE_EXEC << 4; 871 } 872 if (value & 0x8) { 873 tlb->prot |= PAGE_READ; 874 } 875 if (value & 0x10) { 876 tlb->prot |= PAGE_WRITE; 877 } 878 if (value & 0x20) { 879 tlb->prot |= PAGE_EXEC; 880 } 881 break; 882 } 883 } 884 885 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word, 886 target_ulong entry) 887 { 888 ppcemb_tlb_t *tlb; 889 target_ulong ret; 890 int size; 891 892 entry &= 0x3F; 893 tlb = &env->tlb.tlbe[entry]; 894 switch (word) { 895 default: 896 /* Just here to please gcc */ 897 case 0: 898 ret = tlb->EPN; 899 size = booke_page_size_to_tlb(tlb->size); 900 if (size < 0 || size > 0xF) { 901 size = 1; 902 } 903 ret |= size << 4; 904 if (tlb->attr & 0x1) { 905 ret |= 0x100; 906 } 907 if (tlb->prot & PAGE_VALID) { 908 ret |= 0x200; 909 } 910 env->spr[SPR_440_MMUCR] &= ~0x000000FF; 911 env->spr[SPR_440_MMUCR] |= tlb->PID; 912 break; 913 case 1: 914 ret = tlb->RPN; 915 break; 916 case 2: 917 ret = tlb->attr & ~0x1; 918 if (tlb->prot & (PAGE_READ << 4)) { 919 ret |= 0x1; 920 } 921 if (tlb->prot & (PAGE_WRITE << 4)) { 922 ret |= 0x2; 923 } 924 if (tlb->prot & (PAGE_EXEC << 4)) { 925 ret |= 0x4; 926 } 927 if (tlb->prot & PAGE_READ) { 928 ret |= 0x8; 929 } 930 if (tlb->prot & PAGE_WRITE) { 931 ret |= 0x10; 932 } 933 if (tlb->prot & PAGE_EXEC) { 934 ret |= 0x20; 935 } 936 break; 937 } 938 return ret; 939 } 940 941 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address) 942 { 943 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF); 944 } 945 946 /* PowerPC BookE 2.06 TLB management */ 947 948 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env) 949 { 950 uint32_t tlbncfg = 0; 951 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT; 952 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK); 953 int tlb; 954 955 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT; 956 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb]; 957 958 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) { 959 cpu_abort(env_cpu(env), "we don't support HES yet\n"); 960 } 961 962 return booke206_get_tlbm(env, tlb, ea, esel); 963 } 964 965 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid) 966 { 967 env->spr[pidn] = pid; 968 /* changing PIDs mean we're in a different address space now */ 969 tlb_flush(env_cpu(env)); 970 } 971 972 void helper_booke_set_eplc(CPUPPCState *env, target_ulong val) 973 { 974 env->spr[SPR_BOOKE_EPLC] = val & EPID_MASK; 975 tlb_flush_by_mmuidx(env_cpu(env), 1 << PPC_TLB_EPID_LOAD); 976 } 977 void helper_booke_set_epsc(CPUPPCState *env, target_ulong val) 978 { 979 env->spr[SPR_BOOKE_EPSC] = val & EPID_MASK; 980 tlb_flush_by_mmuidx(env_cpu(env), 1 << PPC_TLB_EPID_STORE); 981 } 982 983 static inline void flush_page(CPUPPCState *env, ppcmas_tlb_t *tlb) 984 { 985 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) { 986 tlb_flush_page(env_cpu(env), tlb->mas2 & MAS2_EPN_MASK); 987 } else { 988 tlb_flush(env_cpu(env)); 989 } 990 } 991 992 void helper_booke206_tlbwe(CPUPPCState *env) 993 { 994 uint32_t tlbncfg, tlbn; 995 ppcmas_tlb_t *tlb; 996 uint32_t size_tlb, size_ps; 997 target_ulong mask; 998 999 1000 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) { 1001 case MAS0_WQ_ALWAYS: 1002 /* good to go, write that entry */ 1003 break; 1004 case MAS0_WQ_COND: 1005 /* XXX check if reserved */ 1006 if (0) { 1007 return; 1008 } 1009 break; 1010 case MAS0_WQ_CLR_RSRV: 1011 /* XXX clear entry */ 1012 return; 1013 default: 1014 /* no idea what to do */ 1015 return; 1016 } 1017 1018 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) && 1019 !msr_gs) { 1020 /* XXX we don't support direct LRAT setting yet */ 1021 fprintf(stderr, "cpu: don't support LRAT setting yet\n"); 1022 return; 1023 } 1024 1025 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT; 1026 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn]; 1027 1028 tlb = booke206_cur_tlb(env); 1029 1030 if (!tlb) { 1031 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 1032 POWERPC_EXCP_INVAL | 1033 POWERPC_EXCP_INVAL_INVAL, GETPC()); 1034 } 1035 1036 /* check that we support the targeted size */ 1037 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; 1038 size_ps = booke206_tlbnps(env, tlbn); 1039 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) && 1040 !(size_ps & (1 << size_tlb))) { 1041 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 1042 POWERPC_EXCP_INVAL | 1043 POWERPC_EXCP_INVAL_INVAL, GETPC()); 1044 } 1045 1046 if (msr_gs) { 1047 cpu_abort(env_cpu(env), "missing HV implementation\n"); 1048 } 1049 1050 if (tlb->mas1 & MAS1_VALID) { 1051 /* 1052 * Invalidate the page in QEMU TLB if it was a valid entry. 1053 * 1054 * In "PowerPC e500 Core Family Reference Manual, Rev. 1", 1055 * Section "12.4.2 TLB Write Entry (tlbwe) Instruction": 1056 * (https://www.nxp.com/docs/en/reference-manual/E500CORERM.pdf) 1057 * 1058 * "Note that when an L2 TLB entry is written, it may be displacing an 1059 * already valid entry in the same L2 TLB location (a victim). If a 1060 * valid L1 TLB entry corresponds to the L2 MMU victim entry, that L1 1061 * TLB entry is automatically invalidated." 1062 */ 1063 flush_page(env, tlb); 1064 } 1065 1066 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) | 1067 env->spr[SPR_BOOKE_MAS3]; 1068 tlb->mas1 = env->spr[SPR_BOOKE_MAS1]; 1069 1070 if ((env->spr[SPR_MMUCFG] & MMUCFG_MAVN) == MMUCFG_MAVN_V2) { 1071 /* For TLB which has a fixed size TSIZE is ignored with MAV2 */ 1072 booke206_fixed_size_tlbn(env, tlbn, tlb); 1073 } else { 1074 if (!(tlbncfg & TLBnCFG_AVAIL)) { 1075 /* force !AVAIL TLB entries to correct page size */ 1076 tlb->mas1 &= ~MAS1_TSIZE_MASK; 1077 /* XXX can be configured in MMUCSR0 */ 1078 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12; 1079 } 1080 } 1081 1082 /* Make a mask from TLB size to discard invalid bits in EPN field */ 1083 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); 1084 /* Add a mask for page attributes */ 1085 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E; 1086 1087 if (!msr_cm) { 1088 /* 1089 * Executing a tlbwe instruction in 32-bit mode will set bits 1090 * 0:31 of the TLB EPN field to zero. 1091 */ 1092 mask &= 0xffffffff; 1093 } 1094 1095 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask; 1096 1097 if (!(tlbncfg & TLBnCFG_IPROT)) { 1098 /* no IPROT supported by TLB */ 1099 tlb->mas1 &= ~MAS1_IPROT; 1100 } 1101 1102 flush_page(env, tlb); 1103 } 1104 1105 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb) 1106 { 1107 int tlbn = booke206_tlbm_to_tlbn(env, tlb); 1108 int way = booke206_tlbm_to_way(env, tlb); 1109 1110 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT; 1111 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT; 1112 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; 1113 1114 env->spr[SPR_BOOKE_MAS1] = tlb->mas1; 1115 env->spr[SPR_BOOKE_MAS2] = tlb->mas2; 1116 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3; 1117 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32; 1118 } 1119 1120 void helper_booke206_tlbre(CPUPPCState *env) 1121 { 1122 ppcmas_tlb_t *tlb = NULL; 1123 1124 tlb = booke206_cur_tlb(env); 1125 if (!tlb) { 1126 env->spr[SPR_BOOKE_MAS1] = 0; 1127 } else { 1128 booke206_tlb_to_mas(env, tlb); 1129 } 1130 } 1131 1132 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address) 1133 { 1134 ppcmas_tlb_t *tlb = NULL; 1135 int i, j; 1136 hwaddr raddr; 1137 uint32_t spid, sas; 1138 1139 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT; 1140 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS; 1141 1142 for (i = 0; i < BOOKE206_MAX_TLBN; i++) { 1143 int ways = booke206_tlb_ways(env, i); 1144 1145 for (j = 0; j < ways; j++) { 1146 tlb = booke206_get_tlbm(env, i, address, j); 1147 1148 if (!tlb) { 1149 continue; 1150 } 1151 1152 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) { 1153 continue; 1154 } 1155 1156 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { 1157 continue; 1158 } 1159 1160 booke206_tlb_to_mas(env, tlb); 1161 return; 1162 } 1163 } 1164 1165 /* no entry found, fill with defaults */ 1166 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK; 1167 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK; 1168 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK; 1169 env->spr[SPR_BOOKE_MAS3] = 0; 1170 env->spr[SPR_BOOKE_MAS7] = 0; 1171 1172 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) { 1173 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS; 1174 } 1175 1176 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16) 1177 << MAS1_TID_SHIFT; 1178 1179 /* next victim logic */ 1180 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT; 1181 env->last_way++; 1182 env->last_way &= booke206_tlb_ways(env, 0) - 1; 1183 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; 1184 } 1185 1186 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn, 1187 vaddr ea) 1188 { 1189 int i; 1190 int ways = booke206_tlb_ways(env, tlbn); 1191 target_ulong mask; 1192 1193 for (i = 0; i < ways; i++) { 1194 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i); 1195 if (!tlb) { 1196 continue; 1197 } 1198 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); 1199 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) && 1200 !(tlb->mas1 & MAS1_IPROT)) { 1201 tlb->mas1 &= ~MAS1_VALID; 1202 } 1203 } 1204 } 1205 1206 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address) 1207 { 1208 CPUState *cs; 1209 1210 if (address & 0x4) { 1211 /* flush all entries */ 1212 if (address & 0x8) { 1213 /* flush all of TLB1 */ 1214 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1); 1215 } else { 1216 /* flush all of TLB0 */ 1217 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0); 1218 } 1219 return; 1220 } 1221 1222 if (address & 0x8) { 1223 /* flush TLB1 entries */ 1224 booke206_invalidate_ea_tlb(env, 1, address); 1225 CPU_FOREACH(cs) { 1226 tlb_flush(cs); 1227 } 1228 } else { 1229 /* flush TLB0 entries */ 1230 booke206_invalidate_ea_tlb(env, 0, address); 1231 CPU_FOREACH(cs) { 1232 tlb_flush_page(cs, address & MAS2_EPN_MASK); 1233 } 1234 } 1235 } 1236 1237 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address) 1238 { 1239 /* XXX missing LPID handling */ 1240 booke206_flush_tlb(env, -1, 1); 1241 } 1242 1243 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address) 1244 { 1245 int i, j; 1246 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID); 1247 ppcmas_tlb_t *tlb = env->tlb.tlbm; 1248 int tlb_size; 1249 1250 /* XXX missing LPID handling */ 1251 for (i = 0; i < BOOKE206_MAX_TLBN; i++) { 1252 tlb_size = booke206_tlb_size(env, i); 1253 for (j = 0; j < tlb_size; j++) { 1254 if (!(tlb[j].mas1 & MAS1_IPROT) && 1255 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) { 1256 tlb[j].mas1 &= ~MAS1_VALID; 1257 } 1258 } 1259 tlb += booke206_tlb_size(env, i); 1260 } 1261 tlb_flush(env_cpu(env)); 1262 } 1263 1264 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address) 1265 { 1266 int i, j; 1267 ppcmas_tlb_t *tlb; 1268 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID); 1269 int pid = tid >> MAS6_SPID_SHIFT; 1270 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS; 1271 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0; 1272 /* XXX check for unsupported isize and raise an invalid opcode then */ 1273 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK; 1274 /* XXX implement MAV2 handling */ 1275 bool mav2 = false; 1276 1277 /* XXX missing LPID handling */ 1278 /* flush by pid and ea */ 1279 for (i = 0; i < BOOKE206_MAX_TLBN; i++) { 1280 int ways = booke206_tlb_ways(env, i); 1281 1282 for (j = 0; j < ways; j++) { 1283 tlb = booke206_get_tlbm(env, i, address, j); 1284 if (!tlb) { 1285 continue; 1286 } 1287 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) || 1288 (tlb->mas1 & MAS1_IPROT) || 1289 ((tlb->mas1 & MAS1_IND) != ind) || 1290 ((tlb->mas8 & MAS8_TGS) != sgs)) { 1291 continue; 1292 } 1293 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) { 1294 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */ 1295 continue; 1296 } 1297 /* XXX e500mc doesn't match SAS, but other cores might */ 1298 tlb->mas1 &= ~MAS1_VALID; 1299 } 1300 } 1301 tlb_flush(env_cpu(env)); 1302 } 1303 1304 void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type) 1305 { 1306 int flags = 0; 1307 1308 if (type & 2) { 1309 flags |= BOOKE206_FLUSH_TLB1; 1310 } 1311 1312 if (type & 4) { 1313 flags |= BOOKE206_FLUSH_TLB0; 1314 } 1315 1316 booke206_flush_tlb(env, flags, 1); 1317 } 1318 1319 1320 void helper_check_tlb_flush_local(CPUPPCState *env) 1321 { 1322 check_tlb_flush(env, false); 1323 } 1324 1325 void helper_check_tlb_flush_global(CPUPPCState *env) 1326 { 1327 check_tlb_flush(env, true); 1328 } 1329 1330 1331 bool ppc_cpu_tlb_fill(CPUState *cs, vaddr eaddr, int size, 1332 MMUAccessType access_type, int mmu_idx, 1333 bool probe, uintptr_t retaddr) 1334 { 1335 PowerPCCPU *cpu = POWERPC_CPU(cs); 1336 hwaddr raddr; 1337 int page_size, prot; 1338 1339 if (ppc_xlate(cpu, eaddr, access_type, &raddr, 1340 &page_size, &prot, mmu_idx, !probe)) { 1341 tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, 1342 prot, mmu_idx, 1UL << page_size); 1343 return true; 1344 } 1345 if (probe) { 1346 return false; 1347 } 1348 raise_exception_err_ra(&cpu->env, cs->exception_index, 1349 cpu->env.error_code, retaddr); 1350 } 1351