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 596 target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */
597 597 target_ulong ptem; /* Virtual segment ID | API */
598 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 96 #define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
97 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 163 static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b,
100 164 target_ulong pte0, target_ulong pte1,
101   - int h, int rw)
  165 + int h, int rw, int type)
102 166 {
103 167 target_ulong ptem, mmask;
104   - int access, ret, pteh, ptev;
  168 + int access, ret, pteh, ptev, pp;
105 169  
106 170 access = 0;
107 171 ret = -1;
... ... @@ -122,11 +186,15 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b,
122 186 if (is_64b) {
123 187 ptem = pte0 & PTE64_PTEM_MASK;
124 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 192 } else
126 193 #endif
127 194 {
128 195 ptem = pte0 & PTE_PTEM_MASK;
129 196 mmask = PTE_CHECK_MASK;
  197 + pp = pte1 & 0x00000003;
130 198 }
131 199 if (ptem == ctx->ptem) {
132 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 206 }
139 207 }
140 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 210 /* Keep the matching PTE informations */
160 211 ctx->raddr = pte1;
161 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 215 /* Access granted */
165 216 #if defined (DEBUG_MMU)
166 217 if (loglevel != 0)
167 218 fprintf(logfile, "PTE access granted !\n");
168 219 #endif
169   - ret = 0;
170 220 } else {
171 221 /* Access right violation */
172 222 #if defined (DEBUG_MMU)
173 223 if (loglevel != 0)
174 224 fprintf(logfile, "PTE access rejected\n");
175 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 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 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 245 #endif
197 246  
... ... @@ -353,7 +402,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
353 402 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
354 403 }
355 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 406 case -3:
358 407 /* TLB inconsistency */
359 408 return -1;
... ... @@ -398,7 +447,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
398 447 {
399 448 target_ulong *BATlt, *BATut, *BATu, *BATl;
400 449 target_ulong base, BEPIl, BEPIu, bl;
401   - int i;
  450 + int i, pp;
402 451 int ret = -1;
403 452  
404 453 #if defined (DEBUG_BATS)
... ... @@ -447,19 +496,23 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
447 496 ctx->raddr = (*BATl & 0xF0000000) |
448 497 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
449 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 508 #if defined (DEBUG_BATS)
455   - if (loglevel != 0) {
  509 + if (ret == 0 && loglevel != 0) {
456 510 fprintf(logfile, "BAT %d match: r 0x" PADDRX
457 511 " prot=%c%c\n",
458 512 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
459 513 ctx->prot & PAGE_WRITE ? 'W' : '-');
460 514 }
461 515 #endif
462   - ret = 0;
463 516 break;
464 517 }
465 518 }
... ... @@ -483,12 +536,14 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
483 536 }
484 537 #endif
485 538 }
  539 +
486 540 /* No hit */
487 541 return ret;
488 542 }
489 543  
490 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 548 target_ulong base, pte0, pte1;
494 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 556 if (is_64b) {
502 557 pte0 = ldq_phys(base + (i * 16));
503 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 560 #if defined (DEBUG_MMU)
506 561 if (loglevel != 0) {
507 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 571 {
517 572 pte0 = ldl_phys(base + (i * 8));
518 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 575 #if defined (DEBUG_MMU)
521 576 if (loglevel != 0) {
522 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 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 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 645 #endif
591 646  
592 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 650 #if defined(TARGET_PPC64)
596 651 if (env->mmu_model == POWERPC_MMU_64B)
597   - return find_pte64(ctx, h, rw);
  652 + return find_pte64(ctx, h, rw, type);
598 653 #endif
599 654  
600   - return find_pte32(ctx, h, rw);
  655 + return find_pte32(ctx, h, rw, type);
601 656 }
602 657  
603 658 #if defined(TARGET_PPC64)
... ... @@ -796,7 +851,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
796 851 #if defined(TARGET_PPC64)
797 852 int attr;
798 853 #endif
799   - int ds, nx, vsid_sh, sdr_sh;
  854 + int ds, vsid_sh, sdr_sh;
800 855 int ret, ret2;
801 856  
802 857 #if defined(TARGET_PPC64)
... ... @@ -812,7 +867,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
812 867 ctx->key = ((attr & 0x40) && msr_pr == 1) ||
813 868 ((attr & 0x80) && msr_pr == 0) ? 1 : 0;
814 869 ds = 0;
815   - nx = attr & 0x20 ? 1 : 0;
  870 + ctx->nx = attr & 0x20 ? 1 : 0;
816 871 vsid_mask = 0x00003FFFFFFFFF80ULL;
817 872 vsid_sh = 7;
818 873 sdr_sh = 18;
... ... @@ -825,7 +880,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
825 880 ctx->key = (((sr & 0x20000000) && msr_pr == 1) ||
826 881 ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
827 882 ds = sr & 0x80000000 ? 1 : 0;
828   - nx = sr & 0x10000000 ? 1 : 0;
  883 + ctx->nx = sr & 0x10000000 ? 1 : 0;
829 884 vsid = sr & 0x00FFFFFF;
830 885 vsid_mask = 0x01FFFFC0;
831 886 vsid_sh = 6;
... ... @@ -844,13 +899,13 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
844 899 #if defined (DEBUG_MMU)
845 900 if (loglevel != 0) {
846 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 904 #endif
850 905 ret = -1;
851 906 if (!ds) {
852 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 909 /* Page address translation */
855 910 /* Primary table address */
856 911 sdr = env->sdr1;
... ... @@ -909,7 +964,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
909 964 }
910 965 #endif
911 966 /* Primary table lookup */
912   - ret = find_pte(env, ctx, 0, rw);
  967 + ret = find_pte(env, ctx, 0, rw, type);
913 968 if (ret < 0) {
914 969 /* Secondary table lookup */
915 970 #if defined (DEBUG_MMU)
... ... @@ -921,7 +976,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
921 976 (uint32_t)hash, ctx->pg_addr[1]);
922 977 }
923 978 #endif
924   - ret2 = find_pte(env, ctx, 1, rw);
  979 + ret2 = find_pte(env, ctx, 1, rw, type);
925 980 if (ret2 != -1)
926 981 ret = ret2;
927 982 }
... ... @@ -1119,76 +1174,32 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
1119 1174 __func__, i, zsel, zpr, rw, tlb->attr);
1120 1175 }
1121 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 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 1204 if (ret >= 0) {
1194 1205 ctx->raddr = raddr;
... ... @@ -1274,7 +1285,7 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx,
1274 1285 int in_plb, ret;
1275 1286  
1276 1287 ctx->raddr = eaddr;
1277   - ctx->prot = PAGE_READ;
  1288 + ctx->prot = PAGE_READ | PAGE_EXEC;
1278 1289 ret = 0;
1279 1290 switch (env->mmu_model) {
1280 1291 case POWERPC_MMU_32B:
... ... @@ -1421,9 +1432,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
1421 1432 }
1422 1433 ret = get_physical_address(env, &ctx, address, rw, access_type, 1);
1423 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 1438 } else if (ret < 0) {
1428 1439 #if defined (DEBUG_MMU)
1429 1440 if (loglevel != 0)
... ...