target/ppc: Add a function to check for page protection bit

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.

Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
This commit is contained in:
BALATON Zoltan 2024-05-13 01:28:07 +02:00 committed by Nicholas Piggin
parent 950251ee7b
commit cd1038ec1d
6 changed files with 29 additions and 37 deletions

View File

@ -7521,6 +7521,11 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->sysemu_ops = &ppc_sysemu_ops; cc->sysemu_ops = &ppc_sysemu_ops;
INTERRUPT_STATS_PROVIDER_CLASS(oc)->get_statistics = ppc_get_irq_stats; 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 #endif
cc->gdb_num_core_regs = 71; cc->gdb_num_core_regs = 71;

View File

@ -234,27 +234,14 @@ void destroy_ppc_opcodes(PowerPCCPU *cpu);
void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc); void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc);
const gchar *ppc_gdb_arch_name(CPUState *cs); 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)
{
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();
}
#ifndef CONFIG_USER_ONLY #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)
{
return prot & (1 << access_type);
}
/* PowerPC MMU emulation */ /* PowerPC MMU emulation */
bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type, bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,

View File

@ -252,7 +252,7 @@ static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
} }
*prot = key ? PAGE_READ | PAGE_WRITE : PAGE_READ; *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; *raddr = eaddr;
return true; return true;
} }
@ -403,7 +403,7 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
if (env->nb_BATs != 0) { if (env->nb_BATs != 0) {
raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx); raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx);
if (raddr != -1) { if (raddr != -1) {
if (prot_for_access_type(access_type) & ~*protp) { if (!check_prot_access_type(*protp, access_type)) {
if (guest_visible) { if (guest_visible) {
if (access_type == MMU_INST_FETCH) { if (access_type == MMU_INST_FETCH) {
cs->exception_index = POWERPC_EXCP_ISI; 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); 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 */ /* Access right violation */
qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
if (guest_visible) { if (guest_visible) {

View File

@ -1089,7 +1089,7 @@ bool ppc_hash64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
amr_prot = ppc_hash64_amr_prot(cpu, pte); amr_prot = ppc_hash64_amr_prot(cpu, pte);
prot = exec_prot & pp_prot & amr_prot; 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) { if (need_prot & ~prot) {
/* Access right violation */ /* Access right violation */
qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");

View File

@ -209,7 +209,7 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
} }
/* Check if requested access type is allowed */ /* 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 */ /* Page Protected for that Access */
*fault_cause |= access_type == MMU_INST_FETCH ? SRR1_NOEXEC_GUARD : *fault_cause |= access_type == MMU_INST_FETCH ? SRR1_NOEXEC_GUARD :
DSISR_PROTFAULT; DSISR_PROTFAULT;

View File

@ -114,11 +114,6 @@ static int pp_check(int key, int pp, int nx)
return access; 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 ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
int way, int is_code) 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 */ /* Keep the matching PTE information */
ctx->raddr = pte1; ctx->raddr = pte1;
ctx->prot = access; ctx->prot = access;
ret = check_prot(ctx->prot, access_type); if (check_prot_access_type(ctx->prot, access_type)) {
if (ret == 0) {
/* Access granted */ /* Access granted */
qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n"); qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
ret = 0;
} else { } else {
/* Access right violation */ /* Access right violation */
qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
ret = -2;
} }
} }
} }
@ -354,12 +350,14 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
(virtual & 0x0001F000); (virtual & 0x0001F000);
/* Compute access rights */ /* Compute access rights */
ctx->prot = prot; ctx->prot = prot;
ret = check_prot(ctx->prot, access_type); if (check_prot_access_type(ctx->prot, access_type)) {
if (ret == 0) {
qemu_log_mask(CPU_LOG_MMU, "BAT %d match: r " HWADDR_FMT_plx qemu_log_mask(CPU_LOG_MMU, "BAT %d match: r " HWADDR_FMT_plx
" prot=%c%c\n", i, ctx->raddr, " prot=%c%c\n", i, ctx->raddr,
ctx->prot & PAGE_READ ? 'R' : '-', ctx->prot & PAGE_READ ? 'R' : '-',
ctx->prot & PAGE_WRITE ? 'W' : '-'); ctx->prot & PAGE_WRITE ? 'W' : '-');
ret = 0;
} else {
ret = -2;
} }
break; break;
} }
@ -576,9 +574,11 @@ static int mmu40x_get_physical_address(CPUPPCState *env, hwaddr *raddr,
check_perms: check_perms:
/* Check from TLB entry */ /* Check from TLB entry */
*prot = tlb->prot; *prot = tlb->prot;
ret = check_prot(*prot, access_type); if (check_prot_access_type(*prot, access_type)) {
if (ret == -2) { ret = 0;
} else {
env->spr[SPR_40x_ESR] = 0; env->spr[SPR_40x_ESR] = 0;
ret = -2;
} }
break; break;
} }
@ -636,7 +636,7 @@ static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
} else { } else {
*prot = (tlb->prot >> 4) & 0xF; *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__); qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
return 0; return 0;
} }
@ -838,7 +838,7 @@ found_tlb:
*prot |= PAGE_EXEC; *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__); qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
return 0; return 0;
} }