diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 674bb3f6d96f44baf86ef3077eb02c7162f46f8e..42fed6ee25559504f4db2d8000d8b2d67ad5092b 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -473,6 +473,11 @@ struct ppc_slb_t { #endif #endif +/* SRR1 error code fields */ + +#define SRR1_PROTFAULT 0x08000000 +#define SRR1_IAMR 0x00200000 + /* Facility Status and Control (FSCR) bits */ #define FSCR_EBB (63 - 56) /* Event-Based Branch Facility */ #define FSCR_TAR (63 - 55) /* Target Address Register */ diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index 368ee60efbe8668927466d8a53e00253bc6c1656..ee94f13481847a0db9ff59d1b54924645d5dea1f 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -343,6 +343,23 @@ static int ppc_hash64_pte_prot(PowerPCCPU *cpu, return prot; } +/* Check the instruction access permissions specified in the IAMR */ +static int ppc_hash64_iamr_prot(PowerPCCPU *cpu, int key) +{ + CPUPPCState *env = &cpu->env; + int iamr_bits = (env->spr[SPR_IAMR] >> 2 * (31 - key)) & 0x3; + + /* + * An instruction fetch is permitted if the IAMR bit is 0. + * If the bit is set, return PAGE_READ | PAGE_WRITE because this bit + * can only take away EXEC permissions not READ or WRITE permissions. + * If bit is cleared return PAGE_READ | PAGE_WRITE | PAGE_EXEC since + * EXEC permissions are allowed. + */ + return (iamr_bits & 0x1) ? PAGE_READ | PAGE_WRITE : + PAGE_READ | PAGE_WRITE | PAGE_EXEC; +} + static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte) { CPUPPCState *env = &cpu->env; @@ -375,6 +392,21 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte) prot &= ~PAGE_READ; } + switch (env->mmu_model) { + /* + * MMU version 2.07 and later support IAMR + * Check if the IAMR allows the instruction access - it will return + * PAGE_EXEC if it doesn't (and thus that bit will be cleared) or 0 + * if it does (and prot will be unchanged indicating execution support). + */ + case POWERPC_MMU_2_07: + case POWERPC_MMU_3_00: + prot &= ppc_hash64_iamr_prot(cpu, key); + break; + default: + break; + } + return prot; } @@ -780,7 +812,14 @@ skip_slb_search: /* Access right violation */ qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); if (rwx == 2) { - ppc_hash64_set_isi(cs, env, 0x08000000); + int srr1 = 0; + if (PAGE_EXEC & ~pp_prot) { + srr1 |= SRR1_PROTFAULT; /* Access violates access authority */ + } + if (PAGE_EXEC & ~amr_prot) { + srr1 |= SRR1_IAMR; /* Access violates virt pg class key prot */ + } + ppc_hash64_set_isi(cs, env, srr1); } else { dsisr = 0; if (need_prot[rwx] & ~pp_prot) {