Commit caa4039ced651551503b709b640bc6066b8eb2c2
1 parent
8b67546f
Code provision for PowerPC 64 MMU model support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3186 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
276 additions
and
65 deletions
target-ppc/helper.c
| @@ -77,24 +77,62 @@ static inline void pte_invalidate (target_ulong *pte0) | @@ -77,24 +77,62 @@ static inline void pte_invalidate (target_ulong *pte0) | ||
| 77 | *pte0 &= ~0x80000000; | 77 | *pte0 &= ~0x80000000; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | +#if defined(TARGET_PPC64) | ||
| 81 | +static inline int pte64_is_valid (target_ulong pte0) | ||
| 82 | +{ | ||
| 83 | + return pte0 & 0x0000000000000001ULL ? 1 : 0; | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +static inline void pte64_invalidate (target_ulong *pte0) | ||
| 87 | +{ | ||
| 88 | + *pte0 &= ~0x0000000000000001ULL; | ||
| 89 | +} | ||
| 90 | +#endif | ||
| 91 | + | ||
| 80 | #define PTE_PTEM_MASK 0x7FFFFFBF | 92 | #define PTE_PTEM_MASK 0x7FFFFFBF |
| 81 | #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B) | 93 | #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B) |
| 94 | +#if defined(TARGET_PPC64) | ||
| 95 | +#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL | ||
| 96 | +#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F) | ||
| 97 | +#endif | ||
| 82 | 98 | ||
| 83 | -static int pte_check (mmu_ctx_t *ctx, | ||
| 84 | - target_ulong pte0, target_ulong pte1, int h, int rw) | 99 | +static inline int _pte_check (mmu_ctx_t *ctx, int is_64b, |
| 100 | + target_ulong pte0, target_ulong pte1, | ||
| 101 | + int h, int rw) | ||
| 85 | { | 102 | { |
| 86 | - int access, ret; | 103 | + target_ulong ptem, mmask; |
| 104 | + int access, ret, pteh, ptev; | ||
| 87 | 105 | ||
| 88 | access = 0; | 106 | access = 0; |
| 89 | ret = -1; | 107 | ret = -1; |
| 90 | /* Check validity and table match */ | 108 | /* Check validity and table match */ |
| 91 | - if (pte_is_valid(pte0) && (h == ((pte0 >> 6) & 1))) { | 109 | +#if defined(TARGET_PPC64) |
| 110 | + if (is_64b) { | ||
| 111 | + ptev = pte64_is_valid(pte0); | ||
| 112 | + pteh = (pte0 >> 1) & 1; | ||
| 113 | + } else | ||
| 114 | +#endif | ||
| 115 | + { | ||
| 116 | + ptev = pte_is_valid(pte0); | ||
| 117 | + pteh = (pte0 >> 6) & 1; | ||
| 118 | + } | ||
| 119 | + if (ptev && h == pteh) { | ||
| 92 | /* Check vsid & api */ | 120 | /* Check vsid & api */ |
| 93 | - if ((pte0 & PTE_PTEM_MASK) == ctx->ptem) { | 121 | +#if defined(TARGET_PPC64) |
| 122 | + if (is_64b) { | ||
| 123 | + ptem = pte0 & PTE64_PTEM_MASK; | ||
| 124 | + mmask = PTE64_CHECK_MASK; | ||
| 125 | + } else | ||
| 126 | +#endif | ||
| 127 | + { | ||
| 128 | + ptem = pte0 & PTE_PTEM_MASK; | ||
| 129 | + mmask = PTE_CHECK_MASK; | ||
| 130 | + } | ||
| 131 | + if (ptem == ctx->ptem) { | ||
| 94 | if (ctx->raddr != (target_ulong)-1) { | 132 | if (ctx->raddr != (target_ulong)-1) { |
| 95 | /* all matches should have equal RPN, WIMG & PP */ | 133 | /* all matches should have equal RPN, WIMG & PP */ |
| 96 | - if ((ctx->raddr & PTE_CHECK_MASK) != (pte1 & PTE_CHECK_MASK)) { | ||
| 97 | - if (loglevel > 0) | 134 | + if ((ctx->raddr & mmask) != (pte1 & mmask)) { |
| 135 | + if (loglevel != 0) | ||
| 98 | fprintf(logfile, "Bad RPN/WIMG/PP\n"); | 136 | fprintf(logfile, "Bad RPN/WIMG/PP\n"); |
| 99 | return -3; | 137 | return -3; |
| 100 | } | 138 | } |
| @@ -143,6 +181,20 @@ static int pte_check (mmu_ctx_t *ctx, | @@ -143,6 +181,20 @@ static int pte_check (mmu_ctx_t *ctx, | ||
| 143 | return ret; | 181 | return ret; |
| 144 | } | 182 | } |
| 145 | 183 | ||
| 184 | +static int pte32_check (mmu_ctx_t *ctx, | ||
| 185 | + target_ulong pte0, target_ulong pte1, int h, int rw) | ||
| 186 | +{ | ||
| 187 | + return _pte_check(ctx, 0, pte0, pte1, h, rw); | ||
| 188 | +} | ||
| 189 | + | ||
| 190 | +#if defined(TARGET_PPC64) | ||
| 191 | +static int pte64_check (mmu_ctx_t *ctx, | ||
| 192 | + target_ulong pte0, target_ulong pte1, int h, int rw) | ||
| 193 | +{ | ||
| 194 | + return _pte_check(ctx, 1, pte0, pte1, h, rw); | ||
| 195 | +} | ||
| 196 | +#endif | ||
| 197 | + | ||
| 146 | static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p, | 198 | static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p, |
| 147 | int ret, int rw) | 199 | int ret, int rw) |
| 148 | { | 200 | { |
| @@ -305,7 +357,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, | @@ -305,7 +357,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, | ||
| 305 | rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D'); | 357 | rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D'); |
| 306 | } | 358 | } |
| 307 | #endif | 359 | #endif |
| 308 | - switch (pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) { | 360 | + switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) { |
| 309 | case -3: | 361 | case -3: |
| 310 | /* TLB inconsistency */ | 362 | /* TLB inconsistency */ |
| 311 | return -1; | 363 | return -1; |
| @@ -440,26 +492,36 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, | @@ -440,26 +492,36 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, | ||
| 440 | } | 492 | } |
| 441 | 493 | ||
| 442 | /* PTE table lookup */ | 494 | /* PTE table lookup */ |
| 443 | -static int find_pte (mmu_ctx_t *ctx, int h, int rw) | 495 | +static inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) |
| 444 | { | 496 | { |
| 445 | target_ulong base, pte0, pte1; | 497 | target_ulong base, pte0, pte1; |
| 446 | int i, good = -1; | 498 | int i, good = -1; |
| 447 | - int ret; | 499 | + int ret, r; |
| 448 | 500 | ||
| 449 | ret = -1; /* No entry found */ | 501 | ret = -1; /* No entry found */ |
| 450 | base = ctx->pg_addr[h]; | 502 | base = ctx->pg_addr[h]; |
| 451 | for (i = 0; i < 8; i++) { | 503 | for (i = 0; i < 8; i++) { |
| 452 | - pte0 = ldl_phys(base + (i * 8)); | ||
| 453 | - pte1 = ldl_phys(base + (i * 8) + 4); | 504 | +#if defined(TARGET_PPC64) |
| 505 | + if (is_64b) { | ||
| 506 | + pte0 = ldq_phys(base + (i * 16)); | ||
| 507 | + pte1 = ldq_phys(base + (i * 16) + 8); | ||
| 508 | + r = pte64_check(ctx, pte0, pte1, h, rw); | ||
| 509 | + } else | ||
| 510 | +#endif | ||
| 511 | + { | ||
| 512 | + pte0 = ldl_phys(base + (i * 8)); | ||
| 513 | + pte1 = ldl_phys(base + (i * 8) + 4); | ||
| 514 | + r = pte32_check(ctx, pte0, pte1, h, rw); | ||
| 515 | + } | ||
| 454 | #if defined (DEBUG_MMU) | 516 | #if defined (DEBUG_MMU) |
| 455 | - if (loglevel > 0) { | 517 | + if (loglevel != 0) { |
| 456 | fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX | 518 | fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX |
| 457 | " 0x" ADDRX " %d %d %d 0x" ADDRX "\n", | 519 | " 0x" ADDRX " %d %d %d 0x" ADDRX "\n", |
| 458 | base + (i * 8), pte0, pte1, | 520 | base + (i * 8), pte0, pte1, |
| 459 | - pte0 >> 31, h, (pte0 >> 6) & 1, ctx->ptem); | 521 | + (int)(pte0 >> 31), h, (int)((pte0 >> 6) & 1), ctx->ptem); |
| 460 | } | 522 | } |
| 461 | #endif | 523 | #endif |
| 462 | - switch (pte_check(ctx, pte0, pte1, h, rw)) { | 524 | + switch (r) { |
| 463 | case -3: | 525 | case -3: |
| 464 | /* PTE inconsistency */ | 526 | /* PTE inconsistency */ |
| 465 | return -1; | 527 | return -1; |
| @@ -494,59 +556,183 @@ static int find_pte (mmu_ctx_t *ctx, int h, int rw) | @@ -494,59 +556,183 @@ static int find_pte (mmu_ctx_t *ctx, int h, int rw) | ||
| 494 | #endif | 556 | #endif |
| 495 | /* Update page flags */ | 557 | /* Update page flags */ |
| 496 | pte1 = ctx->raddr; | 558 | pte1 = ctx->raddr; |
| 497 | - if (pte_update_flags(ctx, &pte1, ret, rw) == 1) | ||
| 498 | - stl_phys_notdirty(base + (good * 8) + 4, pte1); | 559 | + if (pte_update_flags(ctx, &pte1, ret, rw) == 1) { |
| 560 | +#if defined(TARGET_PPC64) | ||
| 561 | + if (is_64b) { | ||
| 562 | + stq_phys_notdirty(base + (good * 16) + 8, pte1); | ||
| 563 | + } else | ||
| 564 | +#endif | ||
| 565 | + { | ||
| 566 | + stl_phys_notdirty(base + (good * 8) + 4, pte1); | ||
| 567 | + } | ||
| 568 | + } | ||
| 499 | } | 569 | } |
| 500 | 570 | ||
| 501 | return ret; | 571 | return ret; |
| 502 | } | 572 | } |
| 503 | 573 | ||
| 574 | +static int find_pte32 (mmu_ctx_t *ctx, int h, int rw) | ||
| 575 | +{ | ||
| 576 | + return _find_pte(ctx, 0, h, rw); | ||
| 577 | +} | ||
| 578 | + | ||
| 579 | +#if defined(TARGET_PPC64) | ||
| 580 | +static int find_pte64 (mmu_ctx_t *ctx, int h, int rw) | ||
| 581 | +{ | ||
| 582 | + return _find_pte(ctx, 1, h, rw); | ||
| 583 | +} | ||
| 584 | +#endif | ||
| 585 | + | ||
| 586 | +static inline int find_pte (CPUState *env, mmu_ctx_t *ctx, int h, int rw) | ||
| 587 | +{ | ||
| 588 | +#if defined(TARGET_PPC64) | ||
| 589 | + if (PPC_MMU(env) == PPC_FLAGS_MMU_64B || | ||
| 590 | + PPC_MMU(env) == PPC_FLAGS_MMU_64BRIDGE) | ||
| 591 | + return find_pte64(ctx, h, rw); | ||
| 592 | +#endif | ||
| 593 | + | ||
| 594 | + return find_pte32(ctx, h, rw); | ||
| 595 | +} | ||
| 596 | + | ||
| 504 | static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1, | 597 | static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1, |
| 598 | + int sdr_sh, | ||
| 505 | target_phys_addr_t hash, | 599 | target_phys_addr_t hash, |
| 506 | target_phys_addr_t mask) | 600 | target_phys_addr_t mask) |
| 507 | { | 601 | { |
| 508 | - return (sdr1 & 0xFFFF0000) | (hash & mask); | 602 | + return (sdr1 & ((target_ulong)(-1ULL) << sdr_sh)) | (hash & mask); |
| 509 | } | 603 | } |
| 510 | 604 | ||
| 605 | +#if defined(TARGET_PPC64) | ||
| 606 | +static int slb_lookup (CPUState *env, target_ulong eaddr, | ||
| 607 | + target_ulong *vsid, target_ulong *page_mask, int *attr) | ||
| 608 | +{ | ||
| 609 | + target_phys_addr_t sr_base; | ||
| 610 | + target_ulong mask; | ||
| 611 | + uint64_t tmp64; | ||
| 612 | + uint32_t tmp; | ||
| 613 | + int n, ret; | ||
| 614 | + int slb_nr; | ||
| 615 | + | ||
| 616 | + ret = -5; | ||
| 617 | + sr_base = env->spr[SPR_ASR]; | ||
| 618 | + mask = 0x0000000000000000ULL; /* Avoid gcc warning */ | ||
| 619 | +#if 0 /* XXX: Fix this */ | ||
| 620 | + slb_nr = env->slb_nr; | ||
| 621 | +#else | ||
| 622 | + slb_nr = 32; | ||
| 623 | +#endif | ||
| 624 | + for (n = 0; n < slb_nr; n++) { | ||
| 625 | + tmp64 = ldq_phys(sr_base); | ||
| 626 | + if (tmp64 & 0x0000000008000000ULL) { | ||
| 627 | + /* SLB entry is valid */ | ||
| 628 | + switch (tmp64 & 0x0000000006000000ULL) { | ||
| 629 | + case 0x0000000000000000ULL: | ||
| 630 | + /* 256 MB segment */ | ||
| 631 | + mask = 0xFFFFFFFFF0000000ULL; | ||
| 632 | + break; | ||
| 633 | + case 0x0000000002000000ULL: | ||
| 634 | + /* 1 TB segment */ | ||
| 635 | + mask = 0xFFFF000000000000ULL; | ||
| 636 | + break; | ||
| 637 | + case 0x0000000004000000ULL: | ||
| 638 | + case 0x0000000006000000ULL: | ||
| 639 | + /* Reserved => segment is invalid */ | ||
| 640 | + continue; | ||
| 641 | + } | ||
| 642 | + if ((eaddr & mask) == (tmp64 & mask)) { | ||
| 643 | + /* SLB match */ | ||
| 644 | + tmp = ldl_phys(sr_base + 8); | ||
| 645 | + *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL; | ||
| 646 | + *page_mask = ~mask; | ||
| 647 | + *attr = tmp & 0xFF; | ||
| 648 | + ret = 0; | ||
| 649 | + break; | ||
| 650 | + } | ||
| 651 | + } | ||
| 652 | + sr_base += 12; | ||
| 653 | + } | ||
| 654 | + | ||
| 655 | + return ret; | ||
| 656 | +} | ||
| 657 | +#endif /* defined(TARGET_PPC64) */ | ||
| 658 | + | ||
| 511 | /* Perform segment based translation */ | 659 | /* Perform segment based translation */ |
| 512 | static int get_segment (CPUState *env, mmu_ctx_t *ctx, | 660 | static int get_segment (CPUState *env, mmu_ctx_t *ctx, |
| 513 | target_ulong eaddr, int rw, int type) | 661 | target_ulong eaddr, int rw, int type) |
| 514 | { | 662 | { |
| 515 | - target_phys_addr_t sdr, hash, mask; | ||
| 516 | - target_ulong sr, vsid, pgidx; | ||
| 517 | - int ret = -1, ret2; | ||
| 518 | - | ||
| 519 | - sr = env->sr[eaddr >> 28]; | ||
| 520 | -#if defined (DEBUG_MMU) | ||
| 521 | - if (loglevel > 0) { | ||
| 522 | - fprintf(logfile, "Check segment v=0x" ADDRX " %d 0x" ADDRX " nip=0x" | ||
| 523 | - ADDRX " lr=0x" ADDRX " ir=%d dr=%d pr=%d %d t=%d\n", | ||
| 524 | - eaddr, eaddr >> 28, sr, env->nip, | ||
| 525 | - env->lr, msr_ir, msr_dr, msr_pr, rw, type); | ||
| 526 | - } | 663 | + target_phys_addr_t sdr, hash, mask, sdr_mask; |
| 664 | + target_ulong sr, vsid, vsid_mask, pgidx, page_mask; | ||
| 665 | +#if defined(TARGET_PPC64) | ||
| 666 | + int attr; | ||
| 527 | #endif | 667 | #endif |
| 528 | - ctx->key = (((sr & 0x20000000) && msr_pr == 1) || | ||
| 529 | - ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; | ||
| 530 | - if ((sr & 0x80000000) == 0) { | 668 | + int ds, nx, vsid_sh, sdr_sh; |
| 669 | + int ret, ret2; | ||
| 670 | + | ||
| 671 | +#if defined(TARGET_PPC64) | ||
| 672 | + if (PPC_MMU(env) == PPC_FLAGS_MMU_64B) { | ||
| 673 | + ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr); | ||
| 674 | + if (ret < 0) | ||
| 675 | + return ret; | ||
| 676 | + ctx->key = ((attr & 0x40) && msr_pr == 1) || | ||
| 677 | + ((attr & 0x80) && msr_pr == 0) ? 1 : 0; | ||
| 678 | + ds = 0; | ||
| 679 | + nx = attr & 0x20 ? 1 : 0; | ||
| 680 | + vsid_mask = 0x00003FFFFFFFFF80ULL; | ||
| 681 | + vsid_sh = 7; | ||
| 682 | + sdr_sh = 18; | ||
| 683 | + sdr_mask = 0x3FF80; | ||
| 684 | + } else | ||
| 685 | +#endif /* defined(TARGET_PPC64) */ | ||
| 686 | + { | ||
| 687 | + sr = env->sr[eaddr >> 28]; | ||
| 688 | + page_mask = 0x0FFFFFFF; | ||
| 689 | + ctx->key = (((sr & 0x20000000) && msr_pr == 1) || | ||
| 690 | + ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; | ||
| 691 | + ds = sr & 0x80000000 ? 1 : 0; | ||
| 692 | + nx = sr & 0x10000000 ? 1 : 0; | ||
| 693 | + vsid = sr & 0x00FFFFFF; | ||
| 694 | + vsid_mask = 0x01FFFFC0; | ||
| 695 | + vsid_sh = 6; | ||
| 696 | + sdr_sh = 16; | ||
| 697 | + sdr_mask = 0xFFC0; | ||
| 531 | #if defined (DEBUG_MMU) | 698 | #if defined (DEBUG_MMU) |
| 532 | - if (loglevel > 0) | 699 | + if (loglevel != 0) { |
| 700 | + fprintf(logfile, "Check segment v=0x" ADDRX " %d 0x" ADDRX | ||
| 701 | + " nip=0x" ADDRX " lr=0x" ADDRX | ||
| 702 | + " ir=%d dr=%d pr=%d %d t=%d\n", | ||
| 703 | + eaddr, (int)(eaddr >> 28), sr, env->nip, | ||
| 704 | + env->lr, msr_ir, msr_dr, msr_pr, rw, type); | ||
| 705 | + } | ||
| 706 | + if (!ds && loglevel != 0) { | ||
| 533 | fprintf(logfile, "pte segment: key=%d n=0x" ADDRX "\n", | 707 | fprintf(logfile, "pte segment: key=%d n=0x" ADDRX "\n", |
| 534 | ctx->key, sr & 0x10000000); | 708 | ctx->key, sr & 0x10000000); |
| 709 | + } | ||
| 535 | #endif | 710 | #endif |
| 711 | + } | ||
| 712 | + ret = -1; | ||
| 713 | + if (!ds) { | ||
| 536 | /* Check if instruction fetch is allowed, if needed */ | 714 | /* Check if instruction fetch is allowed, if needed */ |
| 537 | - if (type != ACCESS_CODE || (sr & 0x10000000) == 0) { | 715 | + if (type != ACCESS_CODE || nx == 0) { |
| 538 | /* Page address translation */ | 716 | /* Page address translation */ |
| 539 | - pgidx = (eaddr >> TARGET_PAGE_BITS) & 0xFFFF; | ||
| 540 | - vsid = sr & 0x00FFFFFF; | ||
| 541 | - hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6; | 717 | + pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS; |
| 718 | + hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; | ||
| 542 | /* Primary table address */ | 719 | /* Primary table address */ |
| 543 | sdr = env->sdr1; | 720 | sdr = env->sdr1; |
| 544 | - mask = ((sdr & 0x000001FF) << 16) | 0xFFC0; | ||
| 545 | - ctx->pg_addr[0] = get_pgaddr(sdr, hash, mask); | 721 | + mask = ((sdr & 0x000001FF) << sdr_sh) | sdr_mask; |
| 722 | + ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask); | ||
| 546 | /* Secondary table address */ | 723 | /* Secondary table address */ |
| 547 | - hash = (~hash) & 0x01FFFFC0; | ||
| 548 | - ctx->pg_addr[1] = get_pgaddr(sdr, hash, mask); | ||
| 549 | - ctx->ptem = (vsid << 7) | (pgidx >> 10); | 724 | + hash = (~hash) & vsid_mask; |
| 725 | + ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask); | ||
| 726 | +#if defined(TARGET_PPC64) | ||
| 727 | + if (PPC_MMU(env) == PPC_FLAGS_MMU_64B || | ||
| 728 | + PPC_MMU(env) == PPC_FLAGS_MMU_64BRIDGE) { | ||
| 729 | + /* Only 5 bits of the page index are used in the AVPN */ | ||
| 730 | + ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80); | ||
| 731 | + } else | ||
| 732 | +#endif | ||
| 733 | + { | ||
| 734 | + ctx->ptem = (vsid << 7) | (pgidx >> 10); | ||
| 735 | + } | ||
| 550 | /* Initialize real address with an invalid value */ | 736 | /* Initialize real address with an invalid value */ |
| 551 | ctx->raddr = (target_ulong)-1; | 737 | ctx->raddr = (target_ulong)-1; |
| 552 | if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { | 738 | if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { |
| @@ -562,7 +748,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | @@ -562,7 +748,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | ||
| 562 | } | 748 | } |
| 563 | #endif | 749 | #endif |
| 564 | /* Primary table lookup */ | 750 | /* Primary table lookup */ |
| 565 | - ret = find_pte(ctx, 0, rw); | 751 | + ret = find_pte(env, ctx, 0, rw); |
| 566 | if (ret < 0) { | 752 | if (ret < 0) { |
| 567 | /* Secondary table lookup */ | 753 | /* Secondary table lookup */ |
| 568 | #if defined (DEBUG_MMU) | 754 | #if defined (DEBUG_MMU) |
| @@ -574,7 +760,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | @@ -574,7 +760,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | ||
| 574 | (uint32_t)hash, ctx->pg_addr[1]); | 760 | (uint32_t)hash, ctx->pg_addr[1]); |
| 575 | } | 761 | } |
| 576 | #endif | 762 | #endif |
| 577 | - ret2 = find_pte(ctx, 1, rw); | 763 | + ret2 = find_pte(env, ctx, 1, rw); |
| 578 | if (ret2 != -1) | 764 | if (ret2 != -1) |
| 579 | ret = ret2; | 765 | ret = ret2; |
| 580 | } | 766 | } |
| @@ -835,29 +1021,54 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, | @@ -835,29 +1021,54 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, | ||
| 835 | ctx->raddr = eaddr; | 1021 | ctx->raddr = eaddr; |
| 836 | ctx->prot = PAGE_READ; | 1022 | ctx->prot = PAGE_READ; |
| 837 | ret = 0; | 1023 | ret = 0; |
| 838 | - if (unlikely(msr_pe != 0 && PPC_MMU(env) == PPC_FLAGS_MMU_403)) { | ||
| 839 | - /* 403 family add some particular protections, | ||
| 840 | - * using PBL/PBU registers for accesses with no translation. | ||
| 841 | - */ | ||
| 842 | - in_plb = | ||
| 843 | - /* Check PLB validity */ | ||
| 844 | - (env->pb[0] < env->pb[1] && | ||
| 845 | - /* and address in plb area */ | ||
| 846 | - eaddr >= env->pb[0] && eaddr < env->pb[1]) || | ||
| 847 | - (env->pb[2] < env->pb[3] && | ||
| 848 | - eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0; | ||
| 849 | - if (in_plb ^ msr_px) { | ||
| 850 | - /* Access in protected area */ | ||
| 851 | - if (rw == 1) { | ||
| 852 | - /* Access is not allowed */ | ||
| 853 | - ret = -2; | 1024 | + switch (PPC_MMU(env)) { |
| 1025 | + case PPC_FLAGS_MMU_32B: | ||
| 1026 | + case PPC_FLAGS_MMU_SOFT_6xx: | ||
| 1027 | + case PPC_FLAGS_MMU_601: | ||
| 1028 | + case PPC_FLAGS_MMU_SOFT_4xx: | ||
| 1029 | + ctx->prot |= PAGE_WRITE; | ||
| 1030 | + break; | ||
| 1031 | +#if defined(TARGET_PPC64) | ||
| 1032 | + case PPC_FLAGS_MMU_64B: | ||
| 1033 | + case PPC_FLAGS_MMU_64BRIDGE: | ||
| 1034 | +#endif | ||
| 1035 | + /* Real address are 60 bits long */ | ||
| 1036 | + ctx->raddr &= 0x0FFFFFFFFFFFFFFFUL; | ||
| 1037 | + ctx->prot |= PAGE_WRITE; | ||
| 1038 | + break; | ||
| 1039 | + case PPC_FLAGS_MMU_403: | ||
| 1040 | + if (unlikely(msr_pe != 0)) { | ||
| 1041 | + /* 403 family add some particular protections, | ||
| 1042 | + * using PBL/PBU registers for accesses with no translation. | ||
| 1043 | + */ | ||
| 1044 | + in_plb = | ||
| 1045 | + /* Check PLB validity */ | ||
| 1046 | + (env->pb[0] < env->pb[1] && | ||
| 1047 | + /* and address in plb area */ | ||
| 1048 | + eaddr >= env->pb[0] && eaddr < env->pb[1]) || | ||
| 1049 | + (env->pb[2] < env->pb[3] && | ||
| 1050 | + eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0; | ||
| 1051 | + if (in_plb ^ msr_px) { | ||
| 1052 | + /* Access in protected area */ | ||
| 1053 | + if (rw == 1) { | ||
| 1054 | + /* Access is not allowed */ | ||
| 1055 | + ret = -2; | ||
| 1056 | + } | ||
| 1057 | + } else { | ||
| 1058 | + /* Read-write access is allowed */ | ||
| 1059 | + ctx->prot |= PAGE_WRITE; | ||
| 854 | } | 1060 | } |
| 855 | - } else { | ||
| 856 | - /* Read-write access is allowed */ | ||
| 857 | - ctx->prot |= PAGE_WRITE; | ||
| 858 | } | 1061 | } |
| 859 | - } else { | 1062 | + case PPC_FLAGS_MMU_BOOKE: |
| 860 | ctx->prot |= PAGE_WRITE; | 1063 | ctx->prot |= PAGE_WRITE; |
| 1064 | + break; | ||
| 1065 | + case PPC_FLAGS_MMU_BOOKE_FSL: | ||
| 1066 | + /* XXX: TODO */ | ||
| 1067 | + cpu_abort(env, "BookE FSL MMU model not implemented\n"); | ||
| 1068 | + break; | ||
| 1069 | + default: | ||
| 1070 | + cpu_abort(env, "Unknown or invalid MMU model\n"); | ||
| 1071 | + return -1; | ||
| 861 | } | 1072 | } |
| 862 | 1073 | ||
| 863 | return ret; | 1074 | return ret; |