By removing cpu details and use a config struct, we can use the same granule_protection_check with other devices, like SMMU.
Signed-off-by: Pierrick Bouvier <[email protected]> --- target/arm/cpu.h | 34 ++++++++++++++++++++++++++++ target/arm/ptw.c | 59 +++++++++++++++++++++++++++++++----------------- 2 files changed, 72 insertions(+), 21 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index efbef0341da..5752e1f58fb 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1216,6 +1216,40 @@ void arm_v7m_cpu_do_interrupt(CPUState *cpu); hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr, MemTxAttrs *attrs); + +typedef struct ARMGranuleProtectionConfig { + /* GPCCR_EL3 */ + uint64_t gpccr; + /* GPTBR_EL3 */ + uint64_t gptbr; + /* ID_AA64MMFR0_EL1.PARange */ + uint8_t parange; + /* FEAT_SEL2 */ + bool support_sel2; + /* Address space to access Granule Protection Table */ + AddressSpace *gpt_as; +} ARMGranuleProtectionConfig; + +/** + * arm_granule_protection_check + * @config: granule protection configuration + * @paddress: address accessed + * @pspace: physical address space accessed + * @ss: security state for access + * @fi: fault information in case a fault is detected + * + * Checks if @paddress can be accessed in physical adress space @pspace + * for @ss secure state, following granule protection setup with @config. + * If a fault is detected, @fi is set accordingly. + * See GranuleProtectionCheck() in A-profile manual. + * + * Returns: true if access is authorized, else false. + */ +bool arm_granule_protection_check(ARMGranuleProtectionConfig config, + uint64_t paddress, + ARMSecuritySpace pspace, + ARMSecuritySpace ss, + ARMMMUFaultInfo *fi); #endif /* !CONFIG_USER_ONLY */ int arm_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 2e6b149b2d1..cdc14b1735b 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -330,26 +330,26 @@ static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx, return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0; } -static bool granule_protection_check(CPUARMState *env, uint64_t paddress, - ARMSecuritySpace pspace, - ARMSecuritySpace ss, - ARMMMUFaultInfo *fi) +bool arm_granule_protection_check(ARMGranuleProtectionConfig config, + uint64_t paddress, + ARMSecuritySpace pspace, + ARMSecuritySpace ss, + ARMMMUFaultInfo *fi) { MemTxAttrs attrs = { .secure = true, .space = ARMSS_Root, }; - ARMCPU *cpu = env_archcpu(env); - uint64_t gpccr = env->cp15.gpccr_el3; + const uint64_t gpccr = config.gpccr; unsigned pps, pgs, l0gptsz, level = 0; uint64_t tableaddr, pps_mask, align, entry, index; - AddressSpace *as; MemTxResult result; int gpi; - if (!FIELD_EX64(gpccr, GPCCR, GPC)) { - return true; - } + /* + * We assume Granule Protection Check is enabled when + * calling this function (GPCCR.GPC == 1). + */ /* * GPC Priority 1 (R_GMGRR): @@ -362,7 +362,7 @@ static bool granule_protection_check(CPUARMState *env, uint64_t paddress, * physical address size is invalid. */ pps = FIELD_EX64(gpccr, GPCCR, PPS); - if (pps > FIELD_EX64_IDREG(&cpu->isar, ID_AA64MMFR0, PARANGE)) { + if (pps > config.parange) { goto fault_walk; } pps = pamax_map[pps]; @@ -432,7 +432,7 @@ static bool granule_protection_check(CPUARMState *env, uint64_t paddress, } /* GPC Priority 4: the base address of GPTBR_EL3 exceeds PPS. */ - tableaddr = env->cp15.gptbr_el3 << 12; + tableaddr = config.gptbr << 12; if (tableaddr & ~pps_mask) { goto fault_size; } @@ -446,12 +446,10 @@ static bool granule_protection_check(CPUARMState *env, uint64_t paddress, align = MAKE_64BIT_MASK(0, align); tableaddr &= ~align; - as = arm_addressspace(env_cpu(env), attrs); - /* Level 0 lookup. */ index = extract64(paddress, l0gptsz, pps - l0gptsz); tableaddr += index * 8; - entry = address_space_ldq_le(as, tableaddr, attrs, &result); + entry = address_space_ldq_le(config.gpt_as, tableaddr, attrs, &result); if (result != MEMTX_OK) { goto fault_eabt; } @@ -479,7 +477,7 @@ static bool granule_protection_check(CPUARMState *env, uint64_t paddress, level = 1; index = extract64(paddress, pgs + 4, l0gptsz - pgs - 4); tableaddr += index * 8; - entry = address_space_ldq_le(as, tableaddr, attrs, &result); + entry = address_space_ldq_le(config.gpt_as, tableaddr, attrs, &result); if (result != MEMTX_OK) { goto fault_eabt; } @@ -513,7 +511,7 @@ static bool granule_protection_check(CPUARMState *env, uint64_t paddress, case 0b1111: /* all access */ return true; case 0b1000: /* secure */ - if (!cpu_isar_feature(aa64_sel2, cpu)) { + if (!config.support_sel2) { goto fault_walk; } /* fall through */ @@ -3786,11 +3784,30 @@ static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw, memop, result, fi)) { return true; } - if (!granule_protection_check(env, result->f.phys_addr, - result->f.attrs.space, ptw->in_space, fi)) { - fi->type = ARMFault_GPCFOnOutput; - return true; + + const uint64_t gpccr = env->cp15.gpccr_el3; + const bool gpc_enabled = FIELD_EX64(gpccr, GPCCR, GPC); + if (gpc_enabled) { + ARMCPU *cpu = env_archcpu(env); + MemTxAttrs attrs = { + .secure = true, + .space = ARMSS_Root, + }; + struct ARMGranuleProtectionConfig config = { + .gpccr = env->cp15.gpccr_el3, + .gptbr = env->cp15.gptbr_el3, + .parange = FIELD_EX64_IDREG(&cpu->isar, ID_AA64MMFR0, PARANGE), + .support_sel2 = cpu_isar_feature(aa64_sel2, cpu), + .gpt_as = arm_addressspace(env_cpu(env), attrs) + }; + if (!arm_granule_protection_check(config, result->f.phys_addr, + result->f.attrs.space, ptw->in_space, + fi)) { + fi->type = ARMFault_GPCFOnOutput; + return true; + } } + return false; } -- 2.47.3
