Commit b227a8e9aa5f27d29f77ba90d5eb9d0662a1175e

Authored by j_mayer
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
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)