mmu_helper.c (40400B)
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 */ 60static 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 78static 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 104static 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 110static 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 */ 130static 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 */ 151static 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 163static 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 185static 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) 197static 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 221static 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 228void 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 255void 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 261void 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 288void 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 294void 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 337void 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 */ 378void 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 case POWERPC_MMU_SOFT_74xx: 389 ppc6xx_tlb_invalidate_all(env); 390 break; 391 case POWERPC_MMU_SOFT_4xx: 392 case POWERPC_MMU_SOFT_4xx_Z: 393 ppc4xx_tlb_invalidate_all(env); 394 break; 395 case POWERPC_MMU_REAL: 396 cpu_abort(env_cpu(env), "No TLB for PowerPC 4xx in real mode\n"); 397 break; 398 case POWERPC_MMU_MPC8xx: 399 /* XXX: TODO */ 400 cpu_abort(env_cpu(env), "MPC8xx MMU model is not implemented\n"); 401 break; 402 case POWERPC_MMU_BOOKE: 403 tlb_flush(env_cpu(env)); 404 break; 405 case POWERPC_MMU_BOOKE206: 406 booke206_flush_tlb(env, -1, 0); 407 break; 408 case POWERPC_MMU_32B: 409 case POWERPC_MMU_601: 410 env->tlb_need_flush = 0; 411 tlb_flush(env_cpu(env)); 412 break; 413 default: 414 /* XXX: TODO */ 415 cpu_abort(env_cpu(env), "Unknown MMU model %x\n", env->mmu_model); 416 break; 417 } 418} 419 420void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) 421{ 422#if !defined(FLUSH_ALL_TLBS) 423 addr &= TARGET_PAGE_MASK; 424#if defined(TARGET_PPC64) 425 if (mmu_is_64bit(env->mmu_model)) { 426 /* tlbie invalidate TLBs for all segments */ 427 /* 428 * XXX: given the fact that there are too many segments to invalidate, 429 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU, 430 * we just invalidate all TLBs 431 */ 432 env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; 433 } else 434#endif /* defined(TARGET_PPC64) */ 435 switch (env->mmu_model) { 436 case POWERPC_MMU_SOFT_6xx: 437 case POWERPC_MMU_SOFT_74xx: 438 ppc6xx_tlb_invalidate_virt(env, addr, 0); 439 if (env->id_tlbs == 1) { 440 ppc6xx_tlb_invalidate_virt(env, addr, 1); 441 } 442 break; 443 case POWERPC_MMU_32B: 444 case POWERPC_MMU_601: 445 /* 446 * Actual CPUs invalidate entire congruence classes based on 447 * the geometry of their TLBs and some OSes take that into 448 * account, we just mark the TLB to be flushed later (context 449 * synchronizing event or sync instruction on 32-bit). 450 */ 451 env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; 452 break; 453 default: 454 /* Should never reach here with other MMU models */ 455 assert(0); 456 } 457#else 458 ppc_tlb_invalidate_all(env); 459#endif 460} 461 462/*****************************************************************************/ 463/* Special registers manipulation */ 464 465/* Segment registers load and store */ 466target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num) 467{ 468#if defined(TARGET_PPC64) 469 if (mmu_is_64bit(env->mmu_model)) { 470 /* XXX */ 471 return 0; 472 } 473#endif 474 return env->sr[sr_num]; 475} 476 477void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value) 478{ 479 qemu_log_mask(CPU_LOG_MMU, 480 "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, 481 (int)srnum, value, env->sr[srnum]); 482#if defined(TARGET_PPC64) 483 if (mmu_is_64bit(env->mmu_model)) { 484 PowerPCCPU *cpu = env_archcpu(env); 485 uint64_t esid, vsid; 486 487 /* ESID = srnum */ 488 esid = ((uint64_t)(srnum & 0xf) << 28) | SLB_ESID_V; 489 490 /* VSID = VSID */ 491 vsid = (value & 0xfffffff) << 12; 492 /* flags = flags */ 493 vsid |= ((value >> 27) & 0xf) << 8; 494 495 ppc_store_slb(cpu, srnum, esid, vsid); 496 } else 497#endif 498 if (env->sr[srnum] != value) { 499 env->sr[srnum] = value; 500 /* 501 * Invalidating 256MB of virtual memory in 4kB pages is way 502 * longer than flushing the whole TLB. 503 */ 504#if !defined(FLUSH_ALL_TLBS) && 0 505 { 506 target_ulong page, end; 507 /* Invalidate 256 MB of virtual memory */ 508 page = (16 << 20) * srnum; 509 end = page + (16 << 20); 510 for (; page != end; page += TARGET_PAGE_SIZE) { 511 tlb_flush_page(env_cpu(env), page); 512 } 513 } 514#else 515 env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; 516#endif 517 } 518} 519 520/* TLB management */ 521void helper_tlbia(CPUPPCState *env) 522{ 523 ppc_tlb_invalidate_all(env); 524} 525 526void helper_tlbie(CPUPPCState *env, target_ulong addr) 527{ 528 ppc_tlb_invalidate_one(env, addr); 529} 530 531void helper_tlbiva(CPUPPCState *env, target_ulong addr) 532{ 533 /* tlbiva instruction only exists on BookE */ 534 assert(env->mmu_model == POWERPC_MMU_BOOKE); 535 /* XXX: TODO */ 536 cpu_abort(env_cpu(env), "BookE MMU model is not implemented\n"); 537} 538 539/* Software driven TLBs management */ 540/* PowerPC 602/603 software TLB load instructions helpers */ 541static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code) 542{ 543 target_ulong RPN, CMP, EPN; 544 int way; 545 546 RPN = env->spr[SPR_RPA]; 547 if (is_code) { 548 CMP = env->spr[SPR_ICMP]; 549 EPN = env->spr[SPR_IMISS]; 550 } else { 551 CMP = env->spr[SPR_DCMP]; 552 EPN = env->spr[SPR_DMISS]; 553 } 554 way = (env->spr[SPR_SRR1] >> 17) & 1; 555 (void)EPN; /* avoid a compiler warning */ 556 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx 557 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP, 558 RPN, way); 559 /* Store this TLB */ 560 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK), 561 way, is_code, CMP, RPN); 562} 563 564void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN) 565{ 566 do_6xx_tlb(env, EPN, 0); 567} 568 569void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN) 570{ 571 do_6xx_tlb(env, EPN, 1); 572} 573 574/* PowerPC 74xx software TLB load instructions helpers */ 575static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code) 576{ 577 target_ulong RPN, CMP, EPN; 578 int way; 579 580 RPN = env->spr[SPR_PTELO]; 581 CMP = env->spr[SPR_PTEHI]; 582 EPN = env->spr[SPR_TLBMISS] & ~0x3; 583 way = env->spr[SPR_TLBMISS] & 0x3; 584 (void)EPN; /* avoid a compiler warning */ 585 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx 586 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP, 587 RPN, way); 588 /* Store this TLB */ 589 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK), 590 way, is_code, CMP, RPN); 591} 592 593void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN) 594{ 595 do_74xx_tlb(env, EPN, 0); 596} 597 598void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN) 599{ 600 do_74xx_tlb(env, EPN, 1); 601} 602 603/*****************************************************************************/ 604/* PowerPC 601 specific instructions (POWER bridge) */ 605 606target_ulong helper_rac(CPUPPCState *env, target_ulong addr) 607{ 608 mmu_ctx_t ctx; 609 int nb_BATs; 610 target_ulong ret = 0; 611 612 /* 613 * We don't have to generate many instances of this instruction, 614 * as rac is supervisor only. 615 * 616 * XXX: FIX THIS: Pretend we have no BAT 617 */ 618 nb_BATs = env->nb_BATs; 619 env->nb_BATs = 0; 620 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) { 621 ret = ctx.raddr; 622 } 623 env->nb_BATs = nb_BATs; 624 return ret; 625} 626 627static inline target_ulong booke_tlb_to_page_size(int size) 628{ 629 return 1024 << (2 * size); 630} 631 632static inline int booke_page_size_to_tlb(target_ulong page_size) 633{ 634 int size; 635 636 switch (page_size) { 637 case 0x00000400UL: 638 size = 0x0; 639 break; 640 case 0x00001000UL: 641 size = 0x1; 642 break; 643 case 0x00004000UL: 644 size = 0x2; 645 break; 646 case 0x00010000UL: 647 size = 0x3; 648 break; 649 case 0x00040000UL: 650 size = 0x4; 651 break; 652 case 0x00100000UL: 653 size = 0x5; 654 break; 655 case 0x00400000UL: 656 size = 0x6; 657 break; 658 case 0x01000000UL: 659 size = 0x7; 660 break; 661 case 0x04000000UL: 662 size = 0x8; 663 break; 664 case 0x10000000UL: 665 size = 0x9; 666 break; 667 case 0x40000000UL: 668 size = 0xA; 669 break; 670#if defined(TARGET_PPC64) 671 case 0x000100000000ULL: 672 size = 0xB; 673 break; 674 case 0x000400000000ULL: 675 size = 0xC; 676 break; 677 case 0x001000000000ULL: 678 size = 0xD; 679 break; 680 case 0x004000000000ULL: 681 size = 0xE; 682 break; 683 case 0x010000000000ULL: 684 size = 0xF; 685 break; 686#endif 687 default: 688 size = -1; 689 break; 690 } 691 692 return size; 693} 694 695/* Helpers for 4xx TLB management */ 696#define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */ 697 698#define PPC4XX_TLBHI_V 0x00000040 699#define PPC4XX_TLBHI_E 0x00000020 700#define PPC4XX_TLBHI_SIZE_MIN 0 701#define PPC4XX_TLBHI_SIZE_MAX 7 702#define PPC4XX_TLBHI_SIZE_DEFAULT 1 703#define PPC4XX_TLBHI_SIZE_SHIFT 7 704#define PPC4XX_TLBHI_SIZE_MASK 0x00000007 705 706#define PPC4XX_TLBLO_EX 0x00000200 707#define PPC4XX_TLBLO_WR 0x00000100 708#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF 709#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00 710 711target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry) 712{ 713 ppcemb_tlb_t *tlb; 714 target_ulong ret; 715 int size; 716 717 entry &= PPC4XX_TLB_ENTRY_MASK; 718 tlb = &env->tlb.tlbe[entry]; 719 ret = tlb->EPN; 720 if (tlb->prot & PAGE_VALID) { 721 ret |= PPC4XX_TLBHI_V; 722 } 723 size = booke_page_size_to_tlb(tlb->size); 724 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) { 725 size = PPC4XX_TLBHI_SIZE_DEFAULT; 726 } 727 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT; 728 env->spr[SPR_40x_PID] = tlb->PID; 729 return ret; 730} 731 732target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry) 733{ 734 ppcemb_tlb_t *tlb; 735 target_ulong ret; 736 737 entry &= PPC4XX_TLB_ENTRY_MASK; 738 tlb = &env->tlb.tlbe[entry]; 739 ret = tlb->RPN; 740 if (tlb->prot & PAGE_EXEC) { 741 ret |= PPC4XX_TLBLO_EX; 742 } 743 if (tlb->prot & PAGE_WRITE) { 744 ret |= PPC4XX_TLBLO_WR; 745 } 746 return ret; 747} 748 749void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry, 750 target_ulong val) 751{ 752 CPUState *cs = env_cpu(env); 753 ppcemb_tlb_t *tlb; 754 target_ulong page, end; 755 756 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry, 757 val); 758 entry &= PPC4XX_TLB_ENTRY_MASK; 759 tlb = &env->tlb.tlbe[entry]; 760 /* Invalidate previous TLB (if it's valid) */ 761 if (tlb->prot & PAGE_VALID) { 762 end = tlb->EPN + tlb->size; 763 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end " 764 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end); 765 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { 766 tlb_flush_page(cs, page); 767 } 768 } 769 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT) 770 & PPC4XX_TLBHI_SIZE_MASK); 771 /* 772 * We cannot handle TLB size < TARGET_PAGE_SIZE. 773 * If this ever occurs, we should implement TARGET_PAGE_BITS_VARY 774 */ 775 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) { 776 cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u " 777 "are not supported (%d)\n" 778 "Please implement TARGET_PAGE_BITS_VARY\n", 779 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7)); 780 } 781 tlb->EPN = val & ~(tlb->size - 1); 782 if (val & PPC4XX_TLBHI_V) { 783 tlb->prot |= PAGE_VALID; 784 if (val & PPC4XX_TLBHI_E) { 785 /* XXX: TO BE FIXED */ 786 cpu_abort(cs, 787 "Little-endian TLB entries are not supported by now\n"); 788 } 789 } else { 790 tlb->prot &= ~PAGE_VALID; 791 } 792 tlb->PID = env->spr[SPR_40x_PID]; /* PID */ 793 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx 794 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__, 795 (int)entry, tlb->RPN, tlb->EPN, tlb->size, 796 tlb->prot & PAGE_READ ? 'r' : '-', 797 tlb->prot & PAGE_WRITE ? 'w' : '-', 798 tlb->prot & PAGE_EXEC ? 'x' : '-', 799 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); 800 /* Invalidate new TLB (if valid) */ 801 if (tlb->prot & PAGE_VALID) { 802 end = tlb->EPN + tlb->size; 803 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end " 804 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end); 805 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { 806 tlb_flush_page(cs, page); 807 } 808 } 809} 810 811void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry, 812 target_ulong val) 813{ 814 ppcemb_tlb_t *tlb; 815 816 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry, 817 val); 818 entry &= PPC4XX_TLB_ENTRY_MASK; 819 tlb = &env->tlb.tlbe[entry]; 820 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK; 821 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK; 822 tlb->prot = PAGE_READ; 823 if (val & PPC4XX_TLBLO_EX) { 824 tlb->prot |= PAGE_EXEC; 825 } 826 if (val & PPC4XX_TLBLO_WR) { 827 tlb->prot |= PAGE_WRITE; 828 } 829 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx 830 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__, 831 (int)entry, tlb->RPN, tlb->EPN, tlb->size, 832 tlb->prot & PAGE_READ ? 'r' : '-', 833 tlb->prot & PAGE_WRITE ? 'w' : '-', 834 tlb->prot & PAGE_EXEC ? 'x' : '-', 835 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); 836} 837 838target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address) 839{ 840 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]); 841} 842 843/* PowerPC 440 TLB management */ 844void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry, 845 target_ulong value) 846{ 847 ppcemb_tlb_t *tlb; 848 target_ulong EPN, RPN, size; 849 int do_flush_tlbs; 850 851 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n", 852 __func__, word, (int)entry, value); 853 do_flush_tlbs = 0; 854 entry &= 0x3F; 855 tlb = &env->tlb.tlbe[entry]; 856 switch (word) { 857 default: 858 /* Just here to please gcc */ 859 case 0: 860 EPN = value & 0xFFFFFC00; 861 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) { 862 do_flush_tlbs = 1; 863 } 864 tlb->EPN = EPN; 865 size = booke_tlb_to_page_size((value >> 4) & 0xF); 866 if ((tlb->prot & PAGE_VALID) && tlb->size < size) { 867 do_flush_tlbs = 1; 868 } 869 tlb->size = size; 870 tlb->attr &= ~0x1; 871 tlb->attr |= (value >> 8) & 1; 872 if (value & 0x200) { 873 tlb->prot |= PAGE_VALID; 874 } else { 875 if (tlb->prot & PAGE_VALID) { 876 tlb->prot &= ~PAGE_VALID; 877 do_flush_tlbs = 1; 878 } 879 } 880 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF; 881 if (do_flush_tlbs) { 882 tlb_flush(env_cpu(env)); 883 } 884 break; 885 case 1: 886 RPN = value & 0xFFFFFC0F; 887 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) { 888 tlb_flush(env_cpu(env)); 889 } 890 tlb->RPN = RPN; 891 break; 892 case 2: 893 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00); 894 tlb->prot = tlb->prot & PAGE_VALID; 895 if (value & 0x1) { 896 tlb->prot |= PAGE_READ << 4; 897 } 898 if (value & 0x2) { 899 tlb->prot |= PAGE_WRITE << 4; 900 } 901 if (value & 0x4) { 902 tlb->prot |= PAGE_EXEC << 4; 903 } 904 if (value & 0x8) { 905 tlb->prot |= PAGE_READ; 906 } 907 if (value & 0x10) { 908 tlb->prot |= PAGE_WRITE; 909 } 910 if (value & 0x20) { 911 tlb->prot |= PAGE_EXEC; 912 } 913 break; 914 } 915} 916 917target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word, 918 target_ulong entry) 919{ 920 ppcemb_tlb_t *tlb; 921 target_ulong ret; 922 int size; 923 924 entry &= 0x3F; 925 tlb = &env->tlb.tlbe[entry]; 926 switch (word) { 927 default: 928 /* Just here to please gcc */ 929 case 0: 930 ret = tlb->EPN; 931 size = booke_page_size_to_tlb(tlb->size); 932 if (size < 0 || size > 0xF) { 933 size = 1; 934 } 935 ret |= size << 4; 936 if (tlb->attr & 0x1) { 937 ret |= 0x100; 938 } 939 if (tlb->prot & PAGE_VALID) { 940 ret |= 0x200; 941 } 942 env->spr[SPR_440_MMUCR] &= ~0x000000FF; 943 env->spr[SPR_440_MMUCR] |= tlb->PID; 944 break; 945 case 1: 946 ret = tlb->RPN; 947 break; 948 case 2: 949 ret = tlb->attr & ~0x1; 950 if (tlb->prot & (PAGE_READ << 4)) { 951 ret |= 0x1; 952 } 953 if (tlb->prot & (PAGE_WRITE << 4)) { 954 ret |= 0x2; 955 } 956 if (tlb->prot & (PAGE_EXEC << 4)) { 957 ret |= 0x4; 958 } 959 if (tlb->prot & PAGE_READ) { 960 ret |= 0x8; 961 } 962 if (tlb->prot & PAGE_WRITE) { 963 ret |= 0x10; 964 } 965 if (tlb->prot & PAGE_EXEC) { 966 ret |= 0x20; 967 } 968 break; 969 } 970 return ret; 971} 972 973target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address) 974{ 975 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF); 976} 977 978/* PowerPC BookE 2.06 TLB management */ 979 980static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env) 981{ 982 uint32_t tlbncfg = 0; 983 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT; 984 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK); 985 int tlb; 986 987 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT; 988 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb]; 989 990 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) { 991 cpu_abort(env_cpu(env), "we don't support HES yet\n"); 992 } 993 994 return booke206_get_tlbm(env, tlb, ea, esel); 995} 996 997void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid) 998{ 999 env->spr[pidn] = pid; 1000 /* changing PIDs mean we're in a different address space now */ 1001 tlb_flush(env_cpu(env)); 1002} 1003 1004void helper_booke_set_eplc(CPUPPCState *env, target_ulong val) 1005{ 1006 env->spr[SPR_BOOKE_EPLC] = val & EPID_MASK; 1007 tlb_flush_by_mmuidx(env_cpu(env), 1 << PPC_TLB_EPID_LOAD); 1008} 1009void helper_booke_set_epsc(CPUPPCState *env, target_ulong val) 1010{ 1011 env->spr[SPR_BOOKE_EPSC] = val & EPID_MASK; 1012 tlb_flush_by_mmuidx(env_cpu(env), 1 << PPC_TLB_EPID_STORE); 1013} 1014 1015static inline void flush_page(CPUPPCState *env, ppcmas_tlb_t *tlb) 1016{ 1017 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) { 1018 tlb_flush_page(env_cpu(env), tlb->mas2 & MAS2_EPN_MASK); 1019 } else { 1020 tlb_flush(env_cpu(env)); 1021 } 1022} 1023 1024void helper_booke206_tlbwe(CPUPPCState *env) 1025{ 1026 uint32_t tlbncfg, tlbn; 1027 ppcmas_tlb_t *tlb; 1028 uint32_t size_tlb, size_ps; 1029 target_ulong mask; 1030 1031 1032 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) { 1033 case MAS0_WQ_ALWAYS: 1034 /* good to go, write that entry */ 1035 break; 1036 case MAS0_WQ_COND: 1037 /* XXX check if reserved */ 1038 if (0) { 1039 return; 1040 } 1041 break; 1042 case MAS0_WQ_CLR_RSRV: 1043 /* XXX clear entry */ 1044 return; 1045 default: 1046 /* no idea what to do */ 1047 return; 1048 } 1049 1050 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) && 1051 !msr_gs) { 1052 /* XXX we don't support direct LRAT setting yet */ 1053 fprintf(stderr, "cpu: don't support LRAT setting yet\n"); 1054 return; 1055 } 1056 1057 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT; 1058 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn]; 1059 1060 tlb = booke206_cur_tlb(env); 1061 1062 if (!tlb) { 1063 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 1064 POWERPC_EXCP_INVAL | 1065 POWERPC_EXCP_INVAL_INVAL, GETPC()); 1066 } 1067 1068 /* check that we support the targeted size */ 1069 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; 1070 size_ps = booke206_tlbnps(env, tlbn); 1071 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) && 1072 !(size_ps & (1 << size_tlb))) { 1073 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 1074 POWERPC_EXCP_INVAL | 1075 POWERPC_EXCP_INVAL_INVAL, GETPC()); 1076 } 1077 1078 if (msr_gs) { 1079 cpu_abort(env_cpu(env), "missing HV implementation\n"); 1080 } 1081 1082 if (tlb->mas1 & MAS1_VALID) { 1083 /* 1084 * Invalidate the page in QEMU TLB if it was a valid entry. 1085 * 1086 * In "PowerPC e500 Core Family Reference Manual, Rev. 1", 1087 * Section "12.4.2 TLB Write Entry (tlbwe) Instruction": 1088 * (https://www.nxp.com/docs/en/reference-manual/E500CORERM.pdf) 1089 * 1090 * "Note that when an L2 TLB entry is written, it may be displacing an 1091 * already valid entry in the same L2 TLB location (a victim). If a 1092 * valid L1 TLB entry corresponds to the L2 MMU victim entry, that L1 1093 * TLB entry is automatically invalidated." 1094 */ 1095 flush_page(env, tlb); 1096 } 1097 1098 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) | 1099 env->spr[SPR_BOOKE_MAS3]; 1100 tlb->mas1 = env->spr[SPR_BOOKE_MAS1]; 1101 1102 if ((env->spr[SPR_MMUCFG] & MMUCFG_MAVN) == MMUCFG_MAVN_V2) { 1103 /* For TLB which has a fixed size TSIZE is ignored with MAV2 */ 1104 booke206_fixed_size_tlbn(env, tlbn, tlb); 1105 } else { 1106 if (!(tlbncfg & TLBnCFG_AVAIL)) { 1107 /* force !AVAIL TLB entries to correct page size */ 1108 tlb->mas1 &= ~MAS1_TSIZE_MASK; 1109 /* XXX can be configured in MMUCSR0 */ 1110 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12; 1111 } 1112 } 1113 1114 /* Make a mask from TLB size to discard invalid bits in EPN field */ 1115 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); 1116 /* Add a mask for page attributes */ 1117 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E; 1118 1119 if (!msr_cm) { 1120 /* 1121 * Executing a tlbwe instruction in 32-bit mode will set bits 1122 * 0:31 of the TLB EPN field to zero. 1123 */ 1124 mask &= 0xffffffff; 1125 } 1126 1127 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask; 1128 1129 if (!(tlbncfg & TLBnCFG_IPROT)) { 1130 /* no IPROT supported by TLB */ 1131 tlb->mas1 &= ~MAS1_IPROT; 1132 } 1133 1134 flush_page(env, tlb); 1135} 1136 1137static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb) 1138{ 1139 int tlbn = booke206_tlbm_to_tlbn(env, tlb); 1140 int way = booke206_tlbm_to_way(env, tlb); 1141 1142 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT; 1143 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT; 1144 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; 1145 1146 env->spr[SPR_BOOKE_MAS1] = tlb->mas1; 1147 env->spr[SPR_BOOKE_MAS2] = tlb->mas2; 1148 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3; 1149 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32; 1150} 1151 1152void helper_booke206_tlbre(CPUPPCState *env) 1153{ 1154 ppcmas_tlb_t *tlb = NULL; 1155 1156 tlb = booke206_cur_tlb(env); 1157 if (!tlb) { 1158 env->spr[SPR_BOOKE_MAS1] = 0; 1159 } else { 1160 booke206_tlb_to_mas(env, tlb); 1161 } 1162} 1163 1164void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address) 1165{ 1166 ppcmas_tlb_t *tlb = NULL; 1167 int i, j; 1168 hwaddr raddr; 1169 uint32_t spid, sas; 1170 1171 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT; 1172 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS; 1173 1174 for (i = 0; i < BOOKE206_MAX_TLBN; i++) { 1175 int ways = booke206_tlb_ways(env, i); 1176 1177 for (j = 0; j < ways; j++) { 1178 tlb = booke206_get_tlbm(env, i, address, j); 1179 1180 if (!tlb) { 1181 continue; 1182 } 1183 1184 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) { 1185 continue; 1186 } 1187 1188 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { 1189 continue; 1190 } 1191 1192 booke206_tlb_to_mas(env, tlb); 1193 return; 1194 } 1195 } 1196 1197 /* no entry found, fill with defaults */ 1198 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK; 1199 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK; 1200 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK; 1201 env->spr[SPR_BOOKE_MAS3] = 0; 1202 env->spr[SPR_BOOKE_MAS7] = 0; 1203 1204 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) { 1205 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS; 1206 } 1207 1208 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16) 1209 << MAS1_TID_SHIFT; 1210 1211 /* next victim logic */ 1212 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT; 1213 env->last_way++; 1214 env->last_way &= booke206_tlb_ways(env, 0) - 1; 1215 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; 1216} 1217 1218static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn, 1219 uint32_t ea) 1220{ 1221 int i; 1222 int ways = booke206_tlb_ways(env, tlbn); 1223 target_ulong mask; 1224 1225 for (i = 0; i < ways; i++) { 1226 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i); 1227 if (!tlb) { 1228 continue; 1229 } 1230 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); 1231 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) && 1232 !(tlb->mas1 & MAS1_IPROT)) { 1233 tlb->mas1 &= ~MAS1_VALID; 1234 } 1235 } 1236} 1237 1238void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address) 1239{ 1240 CPUState *cs; 1241 1242 if (address & 0x4) { 1243 /* flush all entries */ 1244 if (address & 0x8) { 1245 /* flush all of TLB1 */ 1246 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1); 1247 } else { 1248 /* flush all of TLB0 */ 1249 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0); 1250 } 1251 return; 1252 } 1253 1254 if (address & 0x8) { 1255 /* flush TLB1 entries */ 1256 booke206_invalidate_ea_tlb(env, 1, address); 1257 CPU_FOREACH(cs) { 1258 tlb_flush(cs); 1259 } 1260 } else { 1261 /* flush TLB0 entries */ 1262 booke206_invalidate_ea_tlb(env, 0, address); 1263 CPU_FOREACH(cs) { 1264 tlb_flush_page(cs, address & MAS2_EPN_MASK); 1265 } 1266 } 1267} 1268 1269void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address) 1270{ 1271 /* XXX missing LPID handling */ 1272 booke206_flush_tlb(env, -1, 1); 1273} 1274 1275void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address) 1276{ 1277 int i, j; 1278 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID); 1279 ppcmas_tlb_t *tlb = env->tlb.tlbm; 1280 int tlb_size; 1281 1282 /* XXX missing LPID handling */ 1283 for (i = 0; i < BOOKE206_MAX_TLBN; i++) { 1284 tlb_size = booke206_tlb_size(env, i); 1285 for (j = 0; j < tlb_size; j++) { 1286 if (!(tlb[j].mas1 & MAS1_IPROT) && 1287 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) { 1288 tlb[j].mas1 &= ~MAS1_VALID; 1289 } 1290 } 1291 tlb += booke206_tlb_size(env, i); 1292 } 1293 tlb_flush(env_cpu(env)); 1294} 1295 1296void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address) 1297{ 1298 int i, j; 1299 ppcmas_tlb_t *tlb; 1300 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID); 1301 int pid = tid >> MAS6_SPID_SHIFT; 1302 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS; 1303 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0; 1304 /* XXX check for unsupported isize and raise an invalid opcode then */ 1305 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK; 1306 /* XXX implement MAV2 handling */ 1307 bool mav2 = false; 1308 1309 /* XXX missing LPID handling */ 1310 /* flush by pid and ea */ 1311 for (i = 0; i < BOOKE206_MAX_TLBN; i++) { 1312 int ways = booke206_tlb_ways(env, i); 1313 1314 for (j = 0; j < ways; j++) { 1315 tlb = booke206_get_tlbm(env, i, address, j); 1316 if (!tlb) { 1317 continue; 1318 } 1319 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) || 1320 (tlb->mas1 & MAS1_IPROT) || 1321 ((tlb->mas1 & MAS1_IND) != ind) || 1322 ((tlb->mas8 & MAS8_TGS) != sgs)) { 1323 continue; 1324 } 1325 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) { 1326 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */ 1327 continue; 1328 } 1329 /* XXX e500mc doesn't match SAS, but other cores might */ 1330 tlb->mas1 &= ~MAS1_VALID; 1331 } 1332 } 1333 tlb_flush(env_cpu(env)); 1334} 1335 1336void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type) 1337{ 1338 int flags = 0; 1339 1340 if (type & 2) { 1341 flags |= BOOKE206_FLUSH_TLB1; 1342 } 1343 1344 if (type & 4) { 1345 flags |= BOOKE206_FLUSH_TLB0; 1346 } 1347 1348 booke206_flush_tlb(env, flags, 1); 1349} 1350 1351 1352void helper_check_tlb_flush_local(CPUPPCState *env) 1353{ 1354 check_tlb_flush(env, false); 1355} 1356 1357void helper_check_tlb_flush_global(CPUPPCState *env) 1358{ 1359 check_tlb_flush(env, true); 1360} 1361 1362 1363bool ppc_cpu_tlb_fill(CPUState *cs, vaddr eaddr, int size, 1364 MMUAccessType access_type, int mmu_idx, 1365 bool probe, uintptr_t retaddr) 1366{ 1367 PowerPCCPU *cpu = POWERPC_CPU(cs); 1368 hwaddr raddr; 1369 int page_size, prot; 1370 1371 if (ppc_xlate(cpu, eaddr, access_type, &raddr, 1372 &page_size, &prot, mmu_idx, !probe)) { 1373 tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, 1374 prot, mmu_idx, 1UL << page_size); 1375 return true; 1376 } 1377 if (probe) { 1378 return false; 1379 } 1380 raise_exception_err_ra(&cpu->env, cs->exception_index, 1381 cpu->env.error_code, retaddr); 1382}