On Mon May 13, 2024 at 9:28 AM AEST, BALATON Zoltan wrote:
> Checking if a page protection bit is set for a given access type is a
> common operation. Add a function to avoid repeating the same check at
> multiple places. As this relies on access type and page protection bit
> values having certain relation also add an assert to ensure that this
> assumption holds.
>
> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
> ---
> target/ppc/cpu_init.c | 5 +++++
> target/ppc/internal.h | 23 +++++------------------
> target/ppc/mmu-hash32.c | 6 +++---
> target/ppc/mmu-hash64.c | 2 +-
> target/ppc/mmu-radix64.c | 2 +-
> target/ppc/mmu_common.c | 26 +++++++++++++-------------
> 6 files changed, 28 insertions(+), 36 deletions(-)
>
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index 92c71b2a09..d3b92d9f0e 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -7388,6 +7388,11 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
> #ifndef CONFIG_USER_ONLY
> cc->sysemu_ops = &ppc_sysemu_ops;
> INTERRUPT_STATS_PROVIDER_CLASS(oc)->get_statistics = ppc_get_irq_stats;
> +
> + /* check_prot_access_type relies on MMU access and PAGE bits relations */
> + qemu_build_assert(MMU_DATA_LOAD == 0 && MMU_DATA_STORE == 1 &&
> + MMU_INST_FETCH == 2 && PAGE_READ == 1 &&
> + PAGE_WRITE == 2 && PAGE_EXEC == 4);
> #endif
>
> cc->gdb_num_core_regs = 71;
> diff --git a/target/ppc/internal.h b/target/ppc/internal.h
> index 4a90dd2584..20fb2ec593 100644
> --- a/target/ppc/internal.h
> +++ b/target/ppc/internal.h
> @@ -234,27 +234,14 @@ void destroy_ppc_opcodes(PowerPCCPU *cpu);
> void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc);
> const gchar *ppc_gdb_arch_name(CPUState *cs);
>
> -/**
> - * prot_for_access_type:
> - * @access_type: Access type
> - *
> - * Return the protection bit required for the given access type.
> - */
> -static inline int prot_for_access_type(MMUAccessType access_type)
> +#ifndef CONFIG_USER_ONLY
> +
> +/* Check if permission bit required for the access_type is set in prot */
> +static inline int check_prot_access_type(int prot, MMUAccessType access_type)
> {
> - switch (access_type) {
> - case MMU_INST_FETCH:
> - return PAGE_EXEC;
> - case MMU_DATA_LOAD:
> - return PAGE_READ;
> - case MMU_DATA_STORE:
> - return PAGE_WRITE;
> - }
> - g_assert_not_reached();
> + return prot & (1 << access_type);
I checked and sadly gcc is not able to figure this out on its own yet,
so we'll go with it. Nice improvement.
Reivewed-by: Nicholas Piggin <npiggin@gmail.com>
> }
>
> -#ifndef CONFIG_USER_ONLY
> -
> /* PowerPC MMU emulation */
>
> bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
> diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
> index 3abaf16e78..1e8f1df0f0 100644
> --- a/target/ppc/mmu-hash32.c
> +++ b/target/ppc/mmu-hash32.c
> @@ -252,7 +252,7 @@ static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
> }
>
> *prot = key ? PAGE_READ | PAGE_WRITE : PAGE_READ;
> - if (*prot & prot_for_access_type(access_type)) {
> + if (check_prot_access_type(*prot, access_type)) {
> *raddr = eaddr;
> return true;
> }
> @@ -403,7 +403,7 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
> if (env->nb_BATs != 0) {
> raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx);
> if (raddr != -1) {
> - if (prot_for_access_type(access_type) & ~*protp) {
> + if (!check_prot_access_type(*protp, access_type)) {
> if (guest_visible) {
> if (access_type == MMU_INST_FETCH) {
> cs->exception_index = POWERPC_EXCP_ISI;
> @@ -471,7 +471,7 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
>
> prot = ppc_hash32_pte_prot(mmu_idx, sr, pte);
>
> - if (prot_for_access_type(access_type) & ~prot) {
> + if (!check_prot_access_type(prot, access_type)) {
> /* Access right violation */
> qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
> if (guest_visible) {
> diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> index 0966422a55..d9626f6aab 100644
> --- a/target/ppc/mmu-hash64.c
> +++ b/target/ppc/mmu-hash64.c
> @@ -1097,7 +1097,7 @@ bool ppc_hash64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
> amr_prot = ppc_hash64_amr_prot(cpu, pte);
> prot = exec_prot & pp_prot & amr_prot;
>
> - need_prot = prot_for_access_type(access_type);
> + need_prot = check_prot_access_type(PAGE_RWX, access_type);
> if (need_prot & ~prot) {
> /* Access right violation */
> qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
> diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
> index 395ce3b782..2c5ade5cea 100644
> --- a/target/ppc/mmu-radix64.c
> +++ b/target/ppc/mmu-radix64.c
> @@ -209,7 +209,7 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
> }
>
> /* Check if requested access type is allowed */
> - if (prot_for_access_type(access_type) & ~*prot) {
> + if (!check_prot_access_type(*prot, access_type)) {
> /* Page Protected for that Access */
> *fault_cause |= access_type == MMU_INST_FETCH ? SRR1_NOEXEC_GUARD :
> DSISR_PROTFAULT;
> diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
> index 69f98b7d0e..6746a8ff6b 100644
> --- a/target/ppc/mmu_common.c
> +++ b/target/ppc/mmu_common.c
> @@ -114,11 +114,6 @@ static int pp_check(int key, int pp, int nx)
> return access;
> }
>
> -static int check_prot(int prot, MMUAccessType access_type)
> -{
> - return prot & prot_for_access_type(access_type) ? 0 : -2;
> -}
> -
> int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
> int way, int is_code)
> {
> @@ -165,13 +160,14 @@ static int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
> /* Keep the matching PTE information */
> ctx->raddr = pte1;
> ctx->prot = access;
> - ret = check_prot(ctx->prot, access_type);
> - if (ret == 0) {
> + if (check_prot_access_type(ctx->prot, access_type)) {
> /* Access granted */
> qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
> + ret = 0;
> } else {
> /* Access right violation */
> qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
> + ret = -2;
> }
> }
> }
> @@ -339,12 +335,14 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
> (virtual & 0x0001F000);
> /* Compute access rights */
> ctx->prot = prot;
> - ret = check_prot(ctx->prot, access_type);
> - if (ret == 0) {
> + if (check_prot_access_type(ctx->prot, access_type)) {
> qemu_log_mask(CPU_LOG_MMU, "BAT %d match: r " HWADDR_FMT_plx
> " prot=%c%c\n", i, ctx->raddr,
> ctx->prot & PAGE_READ ? 'R' : '-',
> ctx->prot & PAGE_WRITE ? 'W' : '-');
> + ret = 0;
> + } else {
> + ret = -2;
> }
> break;
> }
> @@ -561,9 +559,11 @@ static int mmu40x_get_physical_address(CPUPPCState *env, hwaddr *raddr,
> check_perms:
> /* Check from TLB entry */
> *prot = tlb->prot;
> - ret = check_prot(*prot, access_type);
> - if (ret == -2) {
> + if (check_prot_access_type(*prot, access_type)) {
> + ret = 0;
> + } else {
> env->spr[SPR_40x_ESR] = 0;
> + ret = -2;
> }
> break;
> }
> @@ -621,7 +621,7 @@ static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
> } else {
> *prot = (tlb->prot >> 4) & 0xF;
> }
> - if (*prot & prot_for_access_type(access_type)) {
> + if (check_prot_access_type(*prot, access_type)) {
> qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
> return 0;
> }
> @@ -823,7 +823,7 @@ found_tlb:
> *prot |= PAGE_EXEC;
> }
> }
> - if (*prot & prot_for_access_type(access_type)) {
> + if (check_prot_access_type(*prot, access_type)) {
> qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
> return 0;
> }