Commit b227a8e9aa5f27d29f77ba90d5eb9d0662a1175e
1 parent
dbdd2506
Properly implement non-execute bit on PowerPC segments and PTEs.
Fix page protection bits for PowerPC 64 MMU. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3395 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
139 additions
and
127 deletions
target-ppc/cpu.h
| @@ -596,6 +596,7 @@ struct mmu_ctx_t { | @@ -596,6 +596,7 @@ struct mmu_ctx_t { | ||
| 596 | target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */ | 596 | target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */ |
| 597 | target_ulong ptem; /* Virtual segment ID | API */ | 597 | target_ulong ptem; /* Virtual segment ID | API */ |
| 598 | int key; /* Access key */ | 598 | int key; /* Access key */ |
| 599 | + int nx; /* Non-execute area */ | ||
| 599 | }; | 600 | }; |
| 600 | 601 | ||
| 601 | /*****************************************************************************/ | 602 | /*****************************************************************************/ |
target-ppc/helper.c
| @@ -96,12 +96,76 @@ static always_inline void pte64_invalidate (target_ulong *pte0) | @@ -96,12 +96,76 @@ static always_inline void pte64_invalidate (target_ulong *pte0) | ||
| 96 | #define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F) | 96 | #define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F) |
| 97 | #endif | 97 | #endif |
| 98 | 98 | ||
| 99 | +static always_inline int pp_check (int key, int pp, int nx) | ||
| 100 | +{ | ||
| 101 | + int access; | ||
| 102 | + | ||
| 103 | + /* Compute access rights */ | ||
| 104 | + /* When pp is 3/7, the result is undefined. Set it to noaccess */ | ||
| 105 | + access = 0; | ||
| 106 | + if (key == 0) { | ||
| 107 | + switch (pp) { | ||
| 108 | + case 0x0: | ||
| 109 | + case 0x1: | ||
| 110 | + case 0x2: | ||
| 111 | + access |= PAGE_WRITE; | ||
| 112 | + /* No break here */ | ||
| 113 | + case 0x3: | ||
| 114 | + case 0x6: | ||
| 115 | + access |= PAGE_READ; | ||
| 116 | + break; | ||
| 117 | + } | ||
| 118 | + } else { | ||
| 119 | + switch (pp) { | ||
| 120 | + case 0x0: | ||
| 121 | + case 0x6: | ||
| 122 | + access = 0; | ||
| 123 | + break; | ||
| 124 | + case 0x1: | ||
| 125 | + case 0x3: | ||
| 126 | + access = PAGE_READ; | ||
| 127 | + break; | ||
| 128 | + case 0x2: | ||
| 129 | + access = PAGE_READ | PAGE_WRITE; | ||
| 130 | + break; | ||
| 131 | + } | ||
| 132 | + } | ||
| 133 | + if (nx == 0) | ||
| 134 | + access |= PAGE_EXEC; | ||
| 135 | + | ||
| 136 | + return access; | ||
| 137 | +} | ||
| 138 | + | ||
| 139 | +static always_inline int check_prot (int prot, int rw, int access_type) | ||
| 140 | +{ | ||
| 141 | + int ret; | ||
| 142 | + | ||
| 143 | + if (access_type == ACCESS_CODE) { | ||
| 144 | + if (prot & PAGE_EXEC) | ||
| 145 | + ret = 0; | ||
| 146 | + else | ||
| 147 | + ret = -2; | ||
| 148 | + } else if (rw) { | ||
| 149 | + if (prot & PAGE_WRITE) | ||
| 150 | + ret = 0; | ||
| 151 | + else | ||
| 152 | + ret = -2; | ||
| 153 | + } else { | ||
| 154 | + if (prot & PAGE_READ) | ||
| 155 | + ret = 0; | ||
| 156 | + else | ||
| 157 | + ret = -2; | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + return ret; | ||
| 161 | +} | ||
| 162 | + | ||
| 99 | static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, | 163 | static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, |
| 100 | target_ulong pte0, target_ulong pte1, | 164 | target_ulong pte0, target_ulong pte1, |
| 101 | - int h, int rw) | 165 | + int h, int rw, int type) |
| 102 | { | 166 | { |
| 103 | target_ulong ptem, mmask; | 167 | target_ulong ptem, mmask; |
| 104 | - int access, ret, pteh, ptev; | 168 | + int access, ret, pteh, ptev, pp; |
| 105 | 169 | ||
| 106 | access = 0; | 170 | access = 0; |
| 107 | ret = -1; | 171 | ret = -1; |
| @@ -122,11 +186,15 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, | @@ -122,11 +186,15 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, | ||
| 122 | if (is_64b) { | 186 | if (is_64b) { |
| 123 | ptem = pte0 & PTE64_PTEM_MASK; | 187 | ptem = pte0 & PTE64_PTEM_MASK; |
| 124 | mmask = PTE64_CHECK_MASK; | 188 | mmask = PTE64_CHECK_MASK; |
| 189 | + pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004); | ||
| 190 | + ctx->nx |= (pte1 >> 2) & 1; /* No execute bit */ | ||
| 191 | + ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */ | ||
| 125 | } else | 192 | } else |
| 126 | #endif | 193 | #endif |
| 127 | { | 194 | { |
| 128 | ptem = pte0 & PTE_PTEM_MASK; | 195 | ptem = pte0 & PTE_PTEM_MASK; |
| 129 | mmask = PTE_CHECK_MASK; | 196 | mmask = PTE_CHECK_MASK; |
| 197 | + pp = pte1 & 0x00000003; | ||
| 130 | } | 198 | } |
| 131 | if (ptem == ctx->ptem) { | 199 | if (ptem == ctx->ptem) { |
| 132 | if (ctx->raddr != (target_ulong)-1) { | 200 | if (ctx->raddr != (target_ulong)-1) { |
| @@ -138,42 +206,23 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, | @@ -138,42 +206,23 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, | ||
| 138 | } | 206 | } |
| 139 | } | 207 | } |
| 140 | /* Compute access rights */ | 208 | /* Compute access rights */ |
| 141 | - if (ctx->key == 0) { | ||
| 142 | - access = PAGE_READ; | ||
| 143 | - if ((pte1 & 0x00000003) != 0x3) | ||
| 144 | - access |= PAGE_WRITE; | ||
| 145 | - } else { | ||
| 146 | - switch (pte1 & 0x00000003) { | ||
| 147 | - case 0x0: | ||
| 148 | - access = 0; | ||
| 149 | - break; | ||
| 150 | - case 0x1: | ||
| 151 | - case 0x3: | ||
| 152 | - access = PAGE_READ; | ||
| 153 | - break; | ||
| 154 | - case 0x2: | ||
| 155 | - access = PAGE_READ | PAGE_WRITE; | ||
| 156 | - break; | ||
| 157 | - } | ||
| 158 | - } | 209 | + access = pp_check(ctx->key, pp, ctx->nx); |
| 159 | /* Keep the matching PTE informations */ | 210 | /* Keep the matching PTE informations */ |
| 160 | ctx->raddr = pte1; | 211 | ctx->raddr = pte1; |
| 161 | ctx->prot = access; | 212 | ctx->prot = access; |
| 162 | - if ((rw == 0 && (access & PAGE_READ)) || | ||
| 163 | - (rw == 1 && (access & PAGE_WRITE))) { | 213 | + ret = check_prot(ctx->prot, rw, type); |
| 214 | + if (ret == 0) { | ||
| 164 | /* Access granted */ | 215 | /* Access granted */ |
| 165 | #if defined (DEBUG_MMU) | 216 | #if defined (DEBUG_MMU) |
| 166 | if (loglevel != 0) | 217 | if (loglevel != 0) |
| 167 | fprintf(logfile, "PTE access granted !\n"); | 218 | fprintf(logfile, "PTE access granted !\n"); |
| 168 | #endif | 219 | #endif |
| 169 | - ret = 0; | ||
| 170 | } else { | 220 | } else { |
| 171 | /* Access right violation */ | 221 | /* Access right violation */ |
| 172 | #if defined (DEBUG_MMU) | 222 | #if defined (DEBUG_MMU) |
| 173 | if (loglevel != 0) | 223 | if (loglevel != 0) |
| 174 | fprintf(logfile, "PTE access rejected\n"); | 224 | fprintf(logfile, "PTE access rejected\n"); |
| 175 | #endif | 225 | #endif |
| 176 | - ret = -2; | ||
| 177 | } | 226 | } |
| 178 | } | 227 | } |
| 179 | } | 228 | } |
| @@ -181,17 +230,17 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, | @@ -181,17 +230,17 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, | ||
| 181 | return ret; | 230 | return ret; |
| 182 | } | 231 | } |
| 183 | 232 | ||
| 184 | -static int pte32_check (mmu_ctx_t *ctx, | ||
| 185 | - target_ulong pte0, target_ulong pte1, int h, int rw) | 233 | +static int pte32_check (mmu_ctx_t *ctx, target_ulong pte0, target_ulong pte1, |
| 234 | + int h, int rw, int type) | ||
| 186 | { | 235 | { |
| 187 | - return _pte_check(ctx, 0, pte0, pte1, h, rw); | 236 | + return _pte_check(ctx, 0, pte0, pte1, h, rw, type); |
| 188 | } | 237 | } |
| 189 | 238 | ||
| 190 | #if defined(TARGET_PPC64) | 239 | #if defined(TARGET_PPC64) |
| 191 | -static int pte64_check (mmu_ctx_t *ctx, | ||
| 192 | - target_ulong pte0, target_ulong pte1, int h, int rw) | 240 | +static int pte64_check (mmu_ctx_t *ctx, target_ulong pte0, target_ulong pte1, |
| 241 | + int h, int rw, int type) | ||
| 193 | { | 242 | { |
| 194 | - return _pte_check(ctx, 1, pte0, pte1, h, rw); | 243 | + return _pte_check(ctx, 1, pte0, pte1, h, rw, type); |
| 195 | } | 244 | } |
| 196 | #endif | 245 | #endif |
| 197 | 246 | ||
| @@ -353,7 +402,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, | @@ -353,7 +402,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, | ||
| 353 | rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D'); | 402 | rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D'); |
| 354 | } | 403 | } |
| 355 | #endif | 404 | #endif |
| 356 | - switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) { | 405 | + switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) { |
| 357 | case -3: | 406 | case -3: |
| 358 | /* TLB inconsistency */ | 407 | /* TLB inconsistency */ |
| 359 | return -1; | 408 | return -1; |
| @@ -398,7 +447,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, | @@ -398,7 +447,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, | ||
| 398 | { | 447 | { |
| 399 | target_ulong *BATlt, *BATut, *BATu, *BATl; | 448 | target_ulong *BATlt, *BATut, *BATu, *BATl; |
| 400 | target_ulong base, BEPIl, BEPIu, bl; | 449 | target_ulong base, BEPIl, BEPIu, bl; |
| 401 | - int i; | 450 | + int i, pp; |
| 402 | int ret = -1; | 451 | int ret = -1; |
| 403 | 452 | ||
| 404 | #if defined (DEBUG_BATS) | 453 | #if defined (DEBUG_BATS) |
| @@ -447,19 +496,23 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, | @@ -447,19 +496,23 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, | ||
| 447 | ctx->raddr = (*BATl & 0xF0000000) | | 496 | ctx->raddr = (*BATl & 0xF0000000) | |
| 448 | ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | | 497 | ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | |
| 449 | (virtual & 0x0001F000); | 498 | (virtual & 0x0001F000); |
| 450 | - if (*BATl & 0x00000001) | ||
| 451 | - ctx->prot = PAGE_READ; | ||
| 452 | - if (*BATl & 0x00000002) | ||
| 453 | - ctx->prot = PAGE_WRITE | PAGE_READ; | 499 | + /* Compute access rights */ |
| 500 | + pp = *BATl & 0x00000003; | ||
| 501 | + ctx->prot = 0; | ||
| 502 | + if (pp != 0) { | ||
| 503 | + ctx->prot = PAGE_READ | PAGE_EXEC; | ||
| 504 | + if (pp == 0x2) | ||
| 505 | + ctx->prot |= PAGE_WRITE; | ||
| 506 | + } | ||
| 507 | + ret = check_prot(ctx->prot, rw, type); | ||
| 454 | #if defined (DEBUG_BATS) | 508 | #if defined (DEBUG_BATS) |
| 455 | - if (loglevel != 0) { | 509 | + if (ret == 0 && loglevel != 0) { |
| 456 | fprintf(logfile, "BAT %d match: r 0x" PADDRX | 510 | fprintf(logfile, "BAT %d match: r 0x" PADDRX |
| 457 | " prot=%c%c\n", | 511 | " prot=%c%c\n", |
| 458 | i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', | 512 | i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', |
| 459 | ctx->prot & PAGE_WRITE ? 'W' : '-'); | 513 | ctx->prot & PAGE_WRITE ? 'W' : '-'); |
| 460 | } | 514 | } |
| 461 | #endif | 515 | #endif |
| 462 | - ret = 0; | ||
| 463 | break; | 516 | break; |
| 464 | } | 517 | } |
| 465 | } | 518 | } |
| @@ -483,12 +536,14 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, | @@ -483,12 +536,14 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, | ||
| 483 | } | 536 | } |
| 484 | #endif | 537 | #endif |
| 485 | } | 538 | } |
| 539 | + | ||
| 486 | /* No hit */ | 540 | /* No hit */ |
| 487 | return ret; | 541 | return ret; |
| 488 | } | 542 | } |
| 489 | 543 | ||
| 490 | /* PTE table lookup */ | 544 | /* PTE table lookup */ |
| 491 | -static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) | 545 | +static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, |
| 546 | + int rw, int type) | ||
| 492 | { | 547 | { |
| 493 | target_ulong base, pte0, pte1; | 548 | target_ulong base, pte0, pte1; |
| 494 | int i, good = -1; | 549 | int i, good = -1; |
| @@ -501,7 +556,7 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) | @@ -501,7 +556,7 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) | ||
| 501 | if (is_64b) { | 556 | if (is_64b) { |
| 502 | pte0 = ldq_phys(base + (i * 16)); | 557 | pte0 = ldq_phys(base + (i * 16)); |
| 503 | pte1 = ldq_phys(base + (i * 16) + 8); | 558 | pte1 = ldq_phys(base + (i * 16) + 8); |
| 504 | - r = pte64_check(ctx, pte0, pte1, h, rw); | 559 | + r = pte64_check(ctx, pte0, pte1, h, rw, type); |
| 505 | #if defined (DEBUG_MMU) | 560 | #if defined (DEBUG_MMU) |
| 506 | if (loglevel != 0) { | 561 | if (loglevel != 0) { |
| 507 | fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX | 562 | fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX |
| @@ -516,7 +571,7 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) | @@ -516,7 +571,7 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) | ||
| 516 | { | 571 | { |
| 517 | pte0 = ldl_phys(base + (i * 8)); | 572 | pte0 = ldl_phys(base + (i * 8)); |
| 518 | pte1 = ldl_phys(base + (i * 8) + 4); | 573 | pte1 = ldl_phys(base + (i * 8) + 4); |
| 519 | - r = pte32_check(ctx, pte0, pte1, h, rw); | 574 | + r = pte32_check(ctx, pte0, pte1, h, rw, type); |
| 520 | #if defined (DEBUG_MMU) | 575 | #if defined (DEBUG_MMU) |
| 521 | if (loglevel != 0) { | 576 | if (loglevel != 0) { |
| 522 | fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX | 577 | fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX |
| @@ -577,27 +632,27 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) | @@ -577,27 +632,27 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) | ||
| 577 | return ret; | 632 | return ret; |
| 578 | } | 633 | } |
| 579 | 634 | ||
| 580 | -static int find_pte32 (mmu_ctx_t *ctx, int h, int rw) | 635 | +static int find_pte32 (mmu_ctx_t *ctx, int h, int rw, int type) |
| 581 | { | 636 | { |
| 582 | - return _find_pte(ctx, 0, h, rw); | 637 | + return _find_pte(ctx, 0, h, rw, type); |
| 583 | } | 638 | } |
| 584 | 639 | ||
| 585 | #if defined(TARGET_PPC64) | 640 | #if defined(TARGET_PPC64) |
| 586 | -static int find_pte64 (mmu_ctx_t *ctx, int h, int rw) | 641 | +static int find_pte64 (mmu_ctx_t *ctx, int h, int rw, int type) |
| 587 | { | 642 | { |
| 588 | - return _find_pte(ctx, 1, h, rw); | 643 | + return _find_pte(ctx, 1, h, rw, type); |
| 589 | } | 644 | } |
| 590 | #endif | 645 | #endif |
| 591 | 646 | ||
| 592 | static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, | 647 | static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, |
| 593 | - int h, int rw) | 648 | + int h, int rw, int type) |
| 594 | { | 649 | { |
| 595 | #if defined(TARGET_PPC64) | 650 | #if defined(TARGET_PPC64) |
| 596 | if (env->mmu_model == POWERPC_MMU_64B) | 651 | if (env->mmu_model == POWERPC_MMU_64B) |
| 597 | - return find_pte64(ctx, h, rw); | 652 | + return find_pte64(ctx, h, rw, type); |
| 598 | #endif | 653 | #endif |
| 599 | 654 | ||
| 600 | - return find_pte32(ctx, h, rw); | 655 | + return find_pte32(ctx, h, rw, type); |
| 601 | } | 656 | } |
| 602 | 657 | ||
| 603 | #if defined(TARGET_PPC64) | 658 | #if defined(TARGET_PPC64) |
| @@ -796,7 +851,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | @@ -796,7 +851,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | ||
| 796 | #if defined(TARGET_PPC64) | 851 | #if defined(TARGET_PPC64) |
| 797 | int attr; | 852 | int attr; |
| 798 | #endif | 853 | #endif |
| 799 | - int ds, nx, vsid_sh, sdr_sh; | 854 | + int ds, vsid_sh, sdr_sh; |
| 800 | int ret, ret2; | 855 | int ret, ret2; |
| 801 | 856 | ||
| 802 | #if defined(TARGET_PPC64) | 857 | #if defined(TARGET_PPC64) |
| @@ -812,7 +867,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | @@ -812,7 +867,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | ||
| 812 | ctx->key = ((attr & 0x40) && msr_pr == 1) || | 867 | ctx->key = ((attr & 0x40) && msr_pr == 1) || |
| 813 | ((attr & 0x80) && msr_pr == 0) ? 1 : 0; | 868 | ((attr & 0x80) && msr_pr == 0) ? 1 : 0; |
| 814 | ds = 0; | 869 | ds = 0; |
| 815 | - nx = attr & 0x20 ? 1 : 0; | 870 | + ctx->nx = attr & 0x20 ? 1 : 0; |
| 816 | vsid_mask = 0x00003FFFFFFFFF80ULL; | 871 | vsid_mask = 0x00003FFFFFFFFF80ULL; |
| 817 | vsid_sh = 7; | 872 | vsid_sh = 7; |
| 818 | sdr_sh = 18; | 873 | sdr_sh = 18; |
| @@ -825,7 +880,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | @@ -825,7 +880,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | ||
| 825 | ctx->key = (((sr & 0x20000000) && msr_pr == 1) || | 880 | ctx->key = (((sr & 0x20000000) && msr_pr == 1) || |
| 826 | ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; | 881 | ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; |
| 827 | ds = sr & 0x80000000 ? 1 : 0; | 882 | ds = sr & 0x80000000 ? 1 : 0; |
| 828 | - nx = sr & 0x10000000 ? 1 : 0; | 883 | + ctx->nx = sr & 0x10000000 ? 1 : 0; |
| 829 | vsid = sr & 0x00FFFFFF; | 884 | vsid = sr & 0x00FFFFFF; |
| 830 | vsid_mask = 0x01FFFFC0; | 885 | vsid_mask = 0x01FFFFC0; |
| 831 | vsid_sh = 6; | 886 | vsid_sh = 6; |
| @@ -844,13 +899,13 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | @@ -844,13 +899,13 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | ||
| 844 | #if defined (DEBUG_MMU) | 899 | #if defined (DEBUG_MMU) |
| 845 | if (loglevel != 0) { | 900 | if (loglevel != 0) { |
| 846 | fprintf(logfile, "pte segment: key=%d ds %d nx %d vsid " ADDRX "\n", | 901 | fprintf(logfile, "pte segment: key=%d ds %d nx %d vsid " ADDRX "\n", |
| 847 | - ctx->key, ds, nx, vsid); | 902 | + ctx->key, ds, ctx->nx, vsid); |
| 848 | } | 903 | } |
| 849 | #endif | 904 | #endif |
| 850 | ret = -1; | 905 | ret = -1; |
| 851 | if (!ds) { | 906 | if (!ds) { |
| 852 | /* Check if instruction fetch is allowed, if needed */ | 907 | /* Check if instruction fetch is allowed, if needed */ |
| 853 | - if (type != ACCESS_CODE || nx == 0) { | 908 | + if (type != ACCESS_CODE || ctx->nx == 0) { |
| 854 | /* Page address translation */ | 909 | /* Page address translation */ |
| 855 | /* Primary table address */ | 910 | /* Primary table address */ |
| 856 | sdr = env->sdr1; | 911 | sdr = env->sdr1; |
| @@ -909,7 +964,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | @@ -909,7 +964,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | ||
| 909 | } | 964 | } |
| 910 | #endif | 965 | #endif |
| 911 | /* Primary table lookup */ | 966 | /* Primary table lookup */ |
| 912 | - ret = find_pte(env, ctx, 0, rw); | 967 | + ret = find_pte(env, ctx, 0, rw, type); |
| 913 | if (ret < 0) { | 968 | if (ret < 0) { |
| 914 | /* Secondary table lookup */ | 969 | /* Secondary table lookup */ |
| 915 | #if defined (DEBUG_MMU) | 970 | #if defined (DEBUG_MMU) |
| @@ -921,7 +976,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | @@ -921,7 +976,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, | ||
| 921 | (uint32_t)hash, ctx->pg_addr[1]); | 976 | (uint32_t)hash, ctx->pg_addr[1]); |
| 922 | } | 977 | } |
| 923 | #endif | 978 | #endif |
| 924 | - ret2 = find_pte(env, ctx, 1, rw); | 979 | + ret2 = find_pte(env, ctx, 1, rw, type); |
| 925 | if (ret2 != -1) | 980 | if (ret2 != -1) |
| 926 | ret = ret2; | 981 | ret = ret2; |
| 927 | } | 982 | } |
| @@ -1119,76 +1174,32 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, | @@ -1119,76 +1174,32 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, | ||
| 1119 | __func__, i, zsel, zpr, rw, tlb->attr); | 1174 | __func__, i, zsel, zpr, rw, tlb->attr); |
| 1120 | } | 1175 | } |
| 1121 | #endif | 1176 | #endif |
| 1122 | - if (access_type == ACCESS_CODE) { | ||
| 1123 | - /* Check execute enable bit */ | ||
| 1124 | - switch (zpr) { | ||
| 1125 | - case 0x2: | ||
| 1126 | - if (msr_pr) | ||
| 1127 | - goto check_exec_perm; | ||
| 1128 | - goto exec_granted; | ||
| 1129 | - case 0x0: | ||
| 1130 | - if (msr_pr) { | ||
| 1131 | - ctx->prot = 0; | ||
| 1132 | - ret = -3; | ||
| 1133 | - break; | ||
| 1134 | - } | ||
| 1135 | - /* No break here */ | ||
| 1136 | - case 0x1: | ||
| 1137 | - check_exec_perm: | ||
| 1138 | - /* Check from TLB entry */ | ||
| 1139 | - if (!(tlb->prot & PAGE_EXEC)) { | ||
| 1140 | - ret = -3; | ||
| 1141 | - } else { | ||
| 1142 | - if (tlb->prot & PAGE_WRITE) { | ||
| 1143 | - ctx->prot = PAGE_READ | PAGE_WRITE; | ||
| 1144 | - } else { | ||
| 1145 | - ctx->prot = PAGE_READ; | ||
| 1146 | - } | ||
| 1147 | - ret = 0; | ||
| 1148 | - } | ||
| 1149 | - break; | ||
| 1150 | - case 0x3: | ||
| 1151 | - exec_granted: | ||
| 1152 | - /* All accesses granted */ | ||
| 1153 | - ctx->prot = PAGE_READ | PAGE_WRITE; | ||
| 1154 | - ret = 0; | ||
| 1155 | - break; | ||
| 1156 | - } | ||
| 1157 | - } else { | ||
| 1158 | - switch (zpr) { | ||
| 1159 | - case 0x2: | ||
| 1160 | - if (msr_pr) | ||
| 1161 | - goto check_rw_perm; | ||
| 1162 | - goto rw_granted; | ||
| 1163 | - case 0x0: | ||
| 1164 | - if (msr_pr) { | ||
| 1165 | - ctx->prot = 0; | ||
| 1166 | - ret = -2; | ||
| 1167 | - break; | ||
| 1168 | - } | ||
| 1169 | - /* No break here */ | ||
| 1170 | - case 0x1: | ||
| 1171 | - check_rw_perm: | ||
| 1172 | - /* Check from TLB entry */ | ||
| 1173 | - /* Check write protection bit */ | ||
| 1174 | - if (tlb->prot & PAGE_WRITE) { | ||
| 1175 | - ctx->prot = PAGE_READ | PAGE_WRITE; | ||
| 1176 | - ret = 0; | ||
| 1177 | - } else { | ||
| 1178 | - ctx->prot = PAGE_READ; | ||
| 1179 | - if (rw) | ||
| 1180 | - ret = -2; | ||
| 1181 | - else | ||
| 1182 | - ret = 0; | ||
| 1183 | - } | ||
| 1184 | - break; | ||
| 1185 | - case 0x3: | ||
| 1186 | - rw_granted: | ||
| 1187 | - /* All accesses granted */ | ||
| 1188 | - ctx->prot = PAGE_READ | PAGE_WRITE; | ||
| 1189 | - ret = 0; | 1177 | + /* Check execute enable bit */ |
| 1178 | + switch (zpr) { | ||
| 1179 | + case 0x2: | ||
| 1180 | + if (msr_pr) | ||
| 1181 | + goto check_perms; | ||
| 1182 | + /* No break here */ | ||
| 1183 | + case 0x3: | ||
| 1184 | + /* All accesses granted */ | ||
| 1185 | + ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | ||
| 1186 | + ret = 0; | ||
| 1187 | + break; | ||
| 1188 | + case 0x0: | ||
| 1189 | + if (msr_pr) { | ||
| 1190 | + ctx->prot = 0; | ||
| 1191 | + ret = -2; | ||
| 1190 | break; | 1192 | break; |
| 1191 | } | 1193 | } |
| 1194 | + /* No break here */ | ||
| 1195 | + case 0x1: | ||
| 1196 | + check_perms: | ||
| 1197 | + /* Check from TLB entry */ | ||
| 1198 | + /* XXX: there is a problem here or in the TLB fill code... */ | ||
| 1199 | + ctx->prot = tlb->prot; | ||
| 1200 | + ctx->prot |= PAGE_EXEC; | ||
| 1201 | + ret = check_prot(ctx->prot, rw, access_type); | ||
| 1202 | + break; | ||
| 1192 | } | 1203 | } |
| 1193 | if (ret >= 0) { | 1204 | if (ret >= 0) { |
| 1194 | ctx->raddr = raddr; | 1205 | ctx->raddr = raddr; |
| @@ -1274,7 +1285,7 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, | @@ -1274,7 +1285,7 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, | ||
| 1274 | int in_plb, ret; | 1285 | int in_plb, ret; |
| 1275 | 1286 | ||
| 1276 | ctx->raddr = eaddr; | 1287 | ctx->raddr = eaddr; |
| 1277 | - ctx->prot = PAGE_READ; | 1288 | + ctx->prot = PAGE_READ | PAGE_EXEC; |
| 1278 | ret = 0; | 1289 | ret = 0; |
| 1279 | switch (env->mmu_model) { | 1290 | switch (env->mmu_model) { |
| 1280 | case POWERPC_MMU_32B: | 1291 | case POWERPC_MMU_32B: |
| @@ -1421,9 +1432,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | @@ -1421,9 +1432,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | ||
| 1421 | } | 1432 | } |
| 1422 | ret = get_physical_address(env, &ctx, address, rw, access_type, 1); | 1433 | ret = get_physical_address(env, &ctx, address, rw, access_type, 1); |
| 1423 | if (ret == 0) { | 1434 | if (ret == 0) { |
| 1424 | - ret = tlb_set_page(env, address & TARGET_PAGE_MASK, | ||
| 1425 | - ctx.raddr & TARGET_PAGE_MASK, ctx.prot, | ||
| 1426 | - mmu_idx, is_softmmu); | 1435 | + ret = tlb_set_page_exec(env, address & TARGET_PAGE_MASK, |
| 1436 | + ctx.raddr & TARGET_PAGE_MASK, ctx.prot, | ||
| 1437 | + mmu_idx, is_softmmu); | ||
| 1427 | } else if (ret < 0) { | 1438 | } else if (ret < 0) { |
| 1428 | #if defined (DEBUG_MMU) | 1439 | #if defined (DEBUG_MMU) |
| 1429 | if (loglevel != 0) | 1440 | if (loglevel != 0) |