ARMv7 SCTLR bit 17 enables hardware management of access flags where the hardware sets AP0 bit of a section or second level table entry upon first access and does not generate a fault.
This patch is an update to earlier patch taking into account different types of page table descriptors when setting the flag. The issue is this had to introduce an extra ldl_phys_ptr call that returns the pointer to page table entry for writing. A better way to do it? Signed-off-by: Bahadir Balban <bbal...@b-labs.co.uk> --- cpu-common.h | 1 + exec.c | 16 ++++++++++++++++ target-arm/helper.c | 17 ++++++++++++++--- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/cpu-common.h b/cpu-common.h index 6302372..96cf67d 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -64,6 +64,7 @@ void cpu_unregister_map_client(void *cookie); uint32_t ldub_phys(target_phys_addr_t addr); uint32_t lduw_phys(target_phys_addr_t addr); uint32_t ldl_phys(target_phys_addr_t addr); +uint32_t *ldl_phys_ptr(target_phys_addr_t addr); uint64_t ldq_phys(target_phys_addr_t addr); void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val); void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val); diff --git a/exec.c b/exec.c index 1190591..cc19586 100644 --- a/exec.c +++ b/exec.c @@ -3346,6 +3346,22 @@ uint32_t ldl_phys(target_phys_addr_t addr) return val; } +uint32_t *ldl_phys_ptr(target_phys_addr_t addr) +{ + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + /* RAM case */ + return qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); +} + /* warning: addr must be aligned */ uint64_t ldq_phys(target_phys_addr_t addr) { diff --git a/target-arm/helper.c b/target-arm/helper.c index 0098053..334832d 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1065,9 +1065,20 @@ static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type, /* The simplified model uses AP[0] as an access control bit. */ if ((env->cp15.c1_sys & (1 << 29)) && (ap & 1) == 0) { - /* Access flag fault. */ - code = (code == 15) ? 6 : 3; - goto do_fault; + /* Is hardware management enabled? */ + if (!(env->cp15.c1_sys & (1 << 17))) { + /* No, access flag fault. */ + code = (code == 15) ? 6 : 3; + goto do_fault; + } else { + /* Set the access flag */ + uint32_t *desc_ptr = ldl_phys_ptr(table); + + if (type == 2) + *desc_ptr |= (1 << 10); /* Section desc */ + else + *desc_ptr |= (1 << 4); /* 4/64k page desc */ + } } *prot = check_ap(env, ap, domain, access_type, is_user); if (!*prot) { -- 1.6.3.3