We had only been reporting the stage2 page size. This causes problems if stage1 is using a larger page size (16k, 2M, etc), but stage2 is using a smaller page size, because cputlb does not set large_page_{addr,mask} properly.
Fix by using the max of the two page sizes. Reported-by: Marc Zyngier <m...@kernel.org> Signed-off-by: Richard Henderson <richard.hender...@linaro.org> --- target/arm/ptw.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 14ab56d1b5..985a5703c3 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -2550,7 +2550,7 @@ static bool get_phys_addr_twostage(CPUARMState *env, target_ulong address, ARMMMUFaultInfo *fi) { hwaddr ipa; - int s1_prot; + int s1_prot, s1_lgpgsz; bool ret, ipa_secure, s2walk_secure; ARMCacheAttrs cacheattrs1; ARMMMUIdx s2_mmu_idx, s2_ptw_idx; @@ -2592,6 +2592,7 @@ static bool get_phys_addr_twostage(CPUARMState *env, target_ulong address, * Save the stage1 results so that we may merge prot and cacheattrs later. */ s1_prot = result->f.prot; + s1_lgpgsz = result->f.lg_page_size; cacheattrs1 = result->cacheattrs; memset(result, 0, sizeof(*result)); @@ -2607,6 +2608,14 @@ static bool get_phys_addr_twostage(CPUARMState *env, target_ulong address, return ret; } + /* + * Use the maximum of the S1 & S2 page size, so that invalidation + * of pages > TARGET_PAGE_SIZE works correctly. + */ + if (result->f.lg_page_size < s1_lgpgsz) { + result->f.lg_page_size = s1_lgpgsz; + } + /* Combine the S1 and S2 cache attributes. */ hcr = arm_hcr_el2_eff_secstate(env, is_secure); if (hcr & HCR_DC) { -- 2.34.1