Revision b227a8e9

b/target-ppc/cpu.h
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
/*****************************************************************************/
b/target-ppc/helper.c
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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)

Also available in: Unified diff