static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, int *prot,
+ target_ulong *page_size,
ARMMMUFaultInfo *fi)
{
ARMCPU *cpu = arm_env_get_cpu(env);
bool is_user = regime_is_user(env, mmu_idx);
*phys_ptr = address;
+ *page_size = TARGET_PAGE_SIZE;
*prot = 0;
if (regime_translation_disabled(env, mmu_idx) ||
rsize++;
}
}
- if (rsize < TARGET_PAGE_BITS) {
- qemu_log_mask(LOG_UNIMP,
- "DRSR[%d]: No support for MPU (sub)region size of"
- " %" PRIu32 " bytes. Minimum is %d.\n",
- n, (1 << rsize), TARGET_PAGE_SIZE);
- continue;
- }
if (srdis) {
continue;
}
+ if (rsize < TARGET_PAGE_BITS) {
+ *page_size = 1 << rsize;
+ }
break;
}
fi->type = ARMFault_Permission;
fi->level = 1;
+ /*
+ * Core QEMU code can't handle execution from small pages yet, so
+ * don't try it. This way we'll get an MPU exception, rather than
+ * eventually causing QEMU to exit in get_page_addr_code().
+ */
+ if (*page_size < TARGET_PAGE_SIZE && (*prot & PAGE_EXEC)) {
+ qemu_log_mask(LOG_UNIMP,
+ "MPU: No support for execution from regions "
+ "smaller than 1K\n");
+ *prot &= ~PAGE_EXEC;
+ }
return !(*prot & (1 << access_type));
}
} else if (arm_feature(env, ARM_FEATURE_V7)) {
/* PMSAv7 */
ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx,
- phys_ptr, prot, fi);
+ phys_ptr, prot, page_size, fi);
} else {
/* Pre-v7 MPU */
ret = get_phys_addr_pmsav5(env, address, access_type, mmu_idx,
core_to_arm_mmu_idx(env, mmu_idx), &phys_addr,
&attrs, &prot, &page_size, fi, NULL);
if (!ret) {
- /* Map a single [sub]page. */
- phys_addr &= TARGET_PAGE_MASK;
- address &= TARGET_PAGE_MASK;
+ /*
+ * Map a single [sub]page. Regions smaller than our declared
+ * target page size are handled specially, so for those we
+ * pass in the exact addresses.
+ */
+ if (page_size >= TARGET_PAGE_SIZE) {
+ phys_addr &= TARGET_PAGE_MASK;
+ address &= TARGET_PAGE_MASK;
+ }
tlb_set_page_with_attrs(cs, address, phys_addr, attrs,
prot, mmu_idx, page_size);
return 0;