diff options
Diffstat (limited to 'target/arm/ptw.c')
-rw-r--r-- | target/arm/ptw.c | 527 |
1 files changed, 322 insertions, 205 deletions
diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 23f16f4ff7..6c5ed56a10 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -9,17 +9,35 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qemu/range.h" +#include "exec/exec-all.h" #include "cpu.h" #include "internals.h" #include "idau.h" -static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - bool is_secure, bool s1_is_el0, +typedef struct S1Translate { + ARMMMUIdx in_mmu_idx; + bool in_secure; + bool in_debug; + bool out_secure; + bool out_be; + hwaddr out_phys; + void *out_host; +} S1Translate; + +static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, + uint64_t address, + MMUAccessType access_type, bool s1_is_el0, GetPhysAddrResult *result, ARMMMUFaultInfo *fi) __attribute__((nonnull)); +static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, + target_ulong address, + MMUAccessType access_type, + GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) + __attribute__((nonnull)); + /* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */ static const uint8_t pamax_map[] = { [0] = 32, @@ -179,6 +197,11 @@ static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx, case ARMMMUIdx_E3: break; + case ARMMMUIdx_Phys_NS: + case ARMMMUIdx_Phys_S: + /* No translation for physical address spaces. */ + return true; + default: g_assert_not_reached(); } @@ -186,7 +209,7 @@ static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx, return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0; } -static bool ptw_attrs_are_device(uint64_t hcr, ARMCacheAttrs cacheattrs) +static bool S2_attrs_are_device(uint64_t hcr, uint8_t attrs) { /* * For an S1 page table walk, the stage 1 attributes are always @@ -197,41 +220,77 @@ static bool ptw_attrs_are_device(uint64_t hcr, ARMCacheAttrs cacheattrs) * With HCR_EL2.FWB == 1 this is when descriptor bit [4] is 0, ie * when cacheattrs.attrs bit [2] is 0. */ - assert(cacheattrs.is_s2_format); if (hcr & HCR_FWB) { - return (cacheattrs.attrs & 0x4) == 0; + return (attrs & 0x4) == 0; } else { - return (cacheattrs.attrs & 0xc) == 0; + return (attrs & 0xc) == 0; } } /* Translate a S1 pagetable walk through S2 if needed. */ -static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, - hwaddr addr, bool *is_secure_ptr, - ARMMMUFaultInfo *fi) +static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, + hwaddr addr, ARMMMUFaultInfo *fi) { - bool is_secure = *is_secure_ptr; + bool is_secure = ptw->in_secure; + ARMMMUIdx mmu_idx = ptw->in_mmu_idx; ARMMMUIdx s2_mmu_idx = is_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2; + bool s2_phys = false; + uint8_t pte_attrs; + bool pte_secure; - if (arm_mmu_idx_is_stage1_of_2(mmu_idx) && - !regime_translation_disabled(env, s2_mmu_idx, is_secure)) { - GetPhysAddrResult s2 = {}; - uint64_t hcr; - int ret; + if (!arm_mmu_idx_is_stage1_of_2(mmu_idx) + || regime_translation_disabled(env, s2_mmu_idx, is_secure)) { + s2_mmu_idx = is_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS; + s2_phys = true; + } - ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, s2_mmu_idx, - is_secure, false, &s2, fi); - if (ret) { - assert(fi->type != ARMFault_None); - fi->s2addr = addr; - fi->stage2 = true; - fi->s1ptw = true; - fi->s1ns = !is_secure; - return ~0; + if (unlikely(ptw->in_debug)) { + /* + * From gdbstub, do not use softmmu so that we don't modify the + * state of the cpu at all, including softmmu tlb contents. + */ + if (s2_phys) { + ptw->out_phys = addr; + pte_attrs = 0; + pte_secure = is_secure; + } else { + S1Translate s2ptw = { + .in_mmu_idx = s2_mmu_idx, + .in_secure = is_secure, + .in_debug = true, + }; + GetPhysAddrResult s2 = { }; + if (!get_phys_addr_lpae(env, &s2ptw, addr, MMU_DATA_LOAD, + false, &s2, fi)) { + goto fail; + } + ptw->out_phys = s2.f.phys_addr; + pte_attrs = s2.cacheattrs.attrs; + pte_secure = s2.f.attrs.secure; } + ptw->out_host = NULL; + } else { + CPUTLBEntryFull *full; + int flags; + + env->tlb_fi = fi; + flags = probe_access_full(env, addr, MMU_DATA_LOAD, + arm_to_core_mmu_idx(s2_mmu_idx), + true, &ptw->out_host, &full, 0); + env->tlb_fi = NULL; + + if (unlikely(flags & TLB_INVALID_MASK)) { + goto fail; + } + ptw->out_phys = full->phys_addr; + pte_attrs = full->pte_attrs; + pte_secure = full->attrs.secure; + } + + if (!s2_phys) { + uint64_t hcr = arm_hcr_el2_eff_secstate(env, is_secure); - hcr = arm_hcr_el2_eff_secstate(env, is_secure); - if ((hcr & HCR_PTW) && ptw_attrs_are_device(hcr, s2.cacheattrs)) { + if ((hcr & HCR_PTW) && S2_attrs_are_device(hcr, pte_attrs)) { /* * PTW set and S1 walk touched S2 Device memory: * generate Permission fault. @@ -241,81 +300,104 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, fi->stage2 = true; fi->s1ptw = true; fi->s1ns = !is_secure; - return ~0; + return false; } + } - if (arm_is_secure_below_el3(env)) { - /* Check if page table walk is to secure or non-secure PA space. */ - if (is_secure) { - is_secure = !(env->cp15.vstcr_el2 & VSTCR_SW); - } else { - is_secure = !(env->cp15.vtcr_el2 & VTCR_NSW); - } - *is_secure_ptr = is_secure; - } else { - assert(!is_secure); - } + /* Check if page table walk is to secure or non-secure PA space. */ + ptw->out_secure = (is_secure + && !(pte_secure + ? env->cp15.vstcr_el2 & VSTCR_SW + : env->cp15.vtcr_el2 & VTCR_NSW)); + ptw->out_be = regime_translation_big_endian(env, mmu_idx); + return true; - addr = s2.f.phys_addr; - } - return addr; + fail: + assert(fi->type != ARMFault_None); + fi->s2addr = addr; + fi->stage2 = true; + fi->s1ptw = true; + fi->s1ns = !is_secure; + return false; } /* All loads done in the course of a page table walk go through here. */ -static uint32_t arm_ldl_ptw(CPUARMState *env, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) +static uint32_t arm_ldl_ptw(CPUARMState *env, S1Translate *ptw, hwaddr addr, + ARMMMUFaultInfo *fi) { CPUState *cs = env_cpu(env); - MemTxAttrs attrs = {}; - MemTxResult result = MEMTX_OK; - AddressSpace *as; uint32_t data; - addr = S1_ptw_translate(env, mmu_idx, addr, &is_secure, fi); - attrs.secure = is_secure; - as = arm_addressspace(cs, attrs); - if (fi->s1ptw) { + if (!S1_ptw_translate(env, ptw, addr, fi)) { + /* Failure. */ + assert(fi->s1ptw); return 0; } - if (regime_translation_big_endian(env, mmu_idx)) { - data = address_space_ldl_be(as, addr, attrs, &result); + + if (likely(ptw->out_host)) { + /* Page tables are in RAM, and we have the host address. */ + if (ptw->out_be) { + data = ldl_be_p(ptw->out_host); + } else { + data = ldl_le_p(ptw->out_host); + } } else { - data = address_space_ldl_le(as, addr, attrs, &result); - } - if (result == MEMTX_OK) { - return data; + /* Page tables are in MMIO. */ + MemTxAttrs attrs = { .secure = ptw->out_secure }; + AddressSpace *as = arm_addressspace(cs, attrs); + MemTxResult result = MEMTX_OK; + + if (ptw->out_be) { + data = address_space_ldl_be(as, ptw->out_phys, attrs, &result); + } else { + data = address_space_ldl_le(as, ptw->out_phys, attrs, &result); + } + if (unlikely(result != MEMTX_OK)) { + fi->type = ARMFault_SyncExternalOnWalk; + fi->ea = arm_extabort_type(result); + return 0; + } } - fi->type = ARMFault_SyncExternalOnWalk; - fi->ea = arm_extabort_type(result); - return 0; + return data; } -static uint64_t arm_ldq_ptw(CPUARMState *env, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) +static uint64_t arm_ldq_ptw(CPUARMState *env, S1Translate *ptw, hwaddr addr, + ARMMMUFaultInfo *fi) { CPUState *cs = env_cpu(env); - MemTxAttrs attrs = {}; - MemTxResult result = MEMTX_OK; - AddressSpace *as; uint64_t data; - addr = S1_ptw_translate(env, mmu_idx, addr, &is_secure, fi); - attrs.secure = is_secure; - as = arm_addressspace(cs, attrs); - if (fi->s1ptw) { + if (!S1_ptw_translate(env, ptw, addr, fi)) { + /* Failure. */ + assert(fi->s1ptw); return 0; } - if (regime_translation_big_endian(env, mmu_idx)) { - data = address_space_ldq_be(as, addr, attrs, &result); + + if (likely(ptw->out_host)) { + /* Page tables are in RAM, and we have the host address. */ + if (ptw->out_be) { + data = ldq_be_p(ptw->out_host); + } else { + data = ldq_le_p(ptw->out_host); + } } else { - data = address_space_ldq_le(as, addr, attrs, &result); - } - if (result == MEMTX_OK) { - return data; + /* Page tables are in MMIO. */ + MemTxAttrs attrs = { .secure = ptw->out_secure }; + AddressSpace *as = arm_addressspace(cs, attrs); + MemTxResult result = MEMTX_OK; + + if (ptw->out_be) { + data = address_space_ldq_be(as, ptw->out_phys, attrs, &result); + } else { + data = address_space_ldq_le(as, ptw->out_phys, attrs, &result); + } + if (unlikely(result != MEMTX_OK)) { + fi->type = ARMFault_SyncExternalOnWalk; + fi->ea = arm_extabort_type(result); + return 0; + } } - fi->type = ARMFault_SyncExternalOnWalk; - fi->ea = arm_extabort_type(result); - return 0; + return data; } static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, @@ -426,10 +508,9 @@ static int simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); } -static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - bool is_secure, GetPhysAddrResult *result, - ARMMMUFaultInfo *fi) +static bool get_phys_addr_v5(CPUARMState *env, S1Translate *ptw, + uint32_t address, MMUAccessType access_type, + GetPhysAddrResult *result, ARMMMUFaultInfo *fi) { int level = 1; uint32_t table; @@ -443,18 +524,18 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, /* Pagetable walk. */ /* Lookup l1 descriptor. */ - if (!get_level1_table_address(env, mmu_idx, &table, address)) { + if (!get_level1_table_address(env, ptw->in_mmu_idx, &table, address)) { /* Section translation fault if page walk is disabled by PD0 or PD1 */ fi->type = ARMFault_Translation; goto do_fault; } - desc = arm_ldl_ptw(env, table, is_secure, mmu_idx, fi); + desc = arm_ldl_ptw(env, ptw, table, fi); if (fi->type != ARMFault_None) { goto do_fault; } type = (desc & 3); domain = (desc >> 5) & 0x0f; - if (regime_el(env, mmu_idx) == 1) { + if (regime_el(env, ptw->in_mmu_idx) == 1) { dacr = env->cp15.dacr_ns; } else { dacr = env->cp15.dacr_s; @@ -486,7 +567,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, /* Fine pagetable. */ table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); } - desc = arm_ldl_ptw(env, table, is_secure, mmu_idx, fi); + desc = arm_ldl_ptw(env, ptw, table, fi); if (fi->type != ARMFault_None) { goto do_fault; } @@ -530,7 +611,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, g_assert_not_reached(); } } - result->f.prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); + result->f.prot = ap_to_rw_prot(env, ptw->in_mmu_idx, ap, domain_prot); result->f.prot |= result->f.prot ? PAGE_EXEC : 0; if (!(result->f.prot & (1 << access_type))) { /* Access permission fault. */ @@ -545,12 +626,12 @@ do_fault: return true; } -static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - bool is_secure, GetPhysAddrResult *result, - ARMMMUFaultInfo *fi) +static bool get_phys_addr_v6(CPUARMState *env, S1Translate *ptw, + uint32_t address, MMUAccessType access_type, + GetPhysAddrResult *result, ARMMMUFaultInfo *fi) { ARMCPU *cpu = env_archcpu(env); + ARMMMUIdx mmu_idx = ptw->in_mmu_idx; int level = 1; uint32_t table; uint32_t desc; @@ -571,7 +652,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, fi->type = ARMFault_Translation; goto do_fault; } - desc = arm_ldl_ptw(env, table, is_secure, mmu_idx, fi); + desc = arm_ldl_ptw(env, ptw, table, fi); if (fi->type != ARMFault_None) { goto do_fault; } @@ -624,7 +705,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, ns = extract32(desc, 3, 1); /* Lookup l2 entry. */ table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); - desc = arm_ldl_ptw(env, table, is_secure, mmu_idx, fi); + desc = arm_ldl_ptw(env, ptw, table, fi); if (fi->type != ARMFault_None) { goto do_fault; } @@ -967,22 +1048,25 @@ static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, * the WnR bit is never set (the caller must do this). * * @env: CPUARMState + * @ptw: Current and next stage parameters for the walk. * @address: virtual address to get physical address for * @access_type: MMU_DATA_LOAD, MMU_DATA_STORE or MMU_INST_FETCH - * @mmu_idx: MMU index indicating required translation regime - * @s1_is_el0: if @mmu_idx is ARMMMUIdx_Stage2 (so this is a stage 2 page - * table walk), must be true if this is stage 2 of a stage 1+2 + * @s1_is_el0: if @ptw->in_mmu_idx is ARMMMUIdx_Stage2 + * (so this is a stage 2 page table walk), + * must be true if this is stage 2 of a stage 1+2 * walk for an EL0 access. If @mmu_idx is anything else, * @s1_is_el0 is ignored. * @result: set on translation success, * @fi: set to fault info if the translation fails */ -static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - bool is_secure, bool s1_is_el0, +static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, + uint64_t address, + MMUAccessType access_type, bool s1_is_el0, GetPhysAddrResult *result, ARMMMUFaultInfo *fi) { ARMCPU *cpu = env_archcpu(env); + ARMMMUIdx mmu_idx = ptw->in_mmu_idx; + bool is_secure = ptw->in_secure; /* Read an LPAE long-descriptor translation table. */ ARMFaultType fault_type = ARMFault_Translation; uint32_t level; @@ -1199,7 +1283,8 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, descaddr |= (address >> (stride * (4 - level))) & indexmask; descaddr &= ~7ULL; nstable = extract32(tableattrs, 4, 1); - descriptor = arm_ldq_ptw(env, descaddr, !nstable, mmu_idx, fi); + ptw->in_secure = !nstable; + descriptor = arm_ldq_ptw(env, ptw, descaddr, fi); if (fi->type != ARMFault_None) { goto do_fault; } @@ -1313,9 +1398,10 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, */ result->f.attrs.secure = false; } - /* When in aarch64 mode, and BTI is enabled, remember GP in the IOTLB. */ - if (aarch64 && guarded && cpu_isar_feature(aa64_bti, cpu)) { - arm_tlb_bti_gp(&result->f.attrs) = true; + + /* When in aarch64 mode, and BTI is enabled, remember GP in the TLB. */ + if (aarch64 && cpu_isar_feature(aa64_bti, cpu)) { + result->f.guarded = guarded; } if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { @@ -2279,10 +2365,17 @@ static bool get_phys_addr_disabled(CPUARMState *env, target_ulong address, { uint8_t memattr = 0x00; /* Device nGnRnE */ uint8_t shareability = 0; /* non-sharable */ + int r_el; - if (mmu_idx != ARMMMUIdx_Stage2 && mmu_idx != ARMMMUIdx_Stage2_S) { - int r_el = regime_el(env, mmu_idx); + switch (mmu_idx) { + case ARMMMUIdx_Stage2: + case ARMMMUIdx_Stage2_S: + case ARMMMUIdx_Phys_NS: + case ARMMMUIdx_Phys_S: + break; + default: + r_el = regime_el(env, mmu_idx); if (arm_el_is_aa64(env, r_el)) { int pamax = arm_pamax(env_archcpu(env)); uint64_t tcr = env->cp15.tcr_el[r_el]; @@ -2331,6 +2424,7 @@ static bool get_phys_addr_disabled(CPUARMState *env, target_ulong address, shareability = 2; /* outer sharable */ } result->cacheattrs.is_s2_format = false; + break; } result->f.phys_addr = address; @@ -2338,111 +2432,116 @@ static bool get_phys_addr_disabled(CPUARMState *env, target_ulong address, result->f.lg_page_size = TARGET_PAGE_BITS; result->cacheattrs.shareability = shareability; result->cacheattrs.attrs = memattr; - return 0; + return false; } -bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - bool is_secure, GetPhysAddrResult *result, - ARMMMUFaultInfo *fi) +static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw, + target_ulong address, + MMUAccessType access_type, + GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) { - ARMMMUIdx s1_mmu_idx = stage_1_mmu_idx(mmu_idx); + hwaddr ipa; + int s1_prot; + bool is_secure = ptw->in_secure; + bool ret, ipa_secure, s2walk_secure; + ARMCacheAttrs cacheattrs1; + bool is_el0; + uint64_t hcr; + + ret = get_phys_addr_with_struct(env, ptw, address, access_type, result, fi); + + /* If S1 fails or S2 is disabled, return early. */ + if (ret || regime_translation_disabled(env, ARMMMUIdx_Stage2, is_secure)) { + return ret; + } - if (mmu_idx != s1_mmu_idx) { - /* - * Call ourselves recursively to do the stage 1 and then stage 2 - * translations if mmu_idx is a two-stage regime. - */ - if (arm_feature(env, ARM_FEATURE_EL2)) { - hwaddr ipa; - int s1_prot; - int ret; - bool ipa_secure, s2walk_secure; - ARMCacheAttrs cacheattrs1; - ARMMMUIdx s2_mmu_idx; - bool is_el0; - uint64_t hcr; - - ret = get_phys_addr_with_secure(env, address, access_type, - s1_mmu_idx, is_secure, result, fi); - - /* If S1 fails or S2 is disabled, return early. */ - if (ret || regime_translation_disabled(env, ARMMMUIdx_Stage2, - is_secure)) { - return ret; - } + ipa = result->f.phys_addr; + ipa_secure = result->f.attrs.secure; + if (is_secure) { + /* Select TCR based on the NS bit from the S1 walk. */ + s2walk_secure = !(ipa_secure + ? env->cp15.vstcr_el2 & VSTCR_SW + : env->cp15.vtcr_el2 & VTCR_NSW); + } else { + assert(!ipa_secure); + s2walk_secure = false; + } - ipa = result->f.phys_addr; - ipa_secure = result->f.attrs.secure; - if (is_secure) { - /* Select TCR based on the NS bit from the S1 walk. */ - s2walk_secure = !(ipa_secure - ? env->cp15.vstcr_el2 & VSTCR_SW - : env->cp15.vtcr_el2 & VTCR_NSW); - } else { - assert(!ipa_secure); - s2walk_secure = false; - } + is_el0 = ptw->in_mmu_idx == ARMMMUIdx_Stage1_E0; + ptw->in_mmu_idx = s2walk_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2; + ptw->in_secure = s2walk_secure; - s2_mmu_idx = (s2walk_secure - ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2); - is_el0 = mmu_idx == ARMMMUIdx_E10_0; + /* + * S1 is done, now do S2 translation. + * Save the stage1 results so that we may merge prot and cacheattrs later. + */ + s1_prot = result->f.prot; + cacheattrs1 = result->cacheattrs; + memset(result, 0, sizeof(*result)); - /* - * S1 is done, now do S2 translation. - * Save the stage1 results so that we may merge - * prot and cacheattrs later. - */ - s1_prot = result->f.prot; - cacheattrs1 = result->cacheattrs; - memset(result, 0, sizeof(*result)); + ret = get_phys_addr_lpae(env, ptw, ipa, access_type, is_el0, result, fi); + fi->s2addr = ipa; - ret = get_phys_addr_lpae(env, ipa, access_type, s2_mmu_idx, - s2walk_secure, is_el0, result, fi); - fi->s2addr = ipa; + /* Combine the S1 and S2 perms. */ + result->f.prot &= s1_prot; - /* Combine the S1 and S2 perms. */ - result->f.prot &= s1_prot; + /* If S2 fails, return early. */ + if (ret) { + return ret; + } - /* If S2 fails, return early. */ - if (ret) { - return ret; - } + /* Combine the S1 and S2 cache attributes. */ + hcr = arm_hcr_el2_eff_secstate(env, is_secure); + if (hcr & HCR_DC) { + /* + * HCR.DC forces the first stage attributes to + * Normal Non-Shareable, + * Inner Write-Back Read-Allocate Write-Allocate, + * Outer Write-Back Read-Allocate Write-Allocate. + * Do not overwrite Tagged within attrs. + */ + if (cacheattrs1.attrs != 0xf0) { + cacheattrs1.attrs = 0xff; + } + cacheattrs1.shareability = 0; + } + result->cacheattrs = combine_cacheattrs(hcr, cacheattrs1, + result->cacheattrs); - /* Combine the S1 and S2 cache attributes. */ - hcr = arm_hcr_el2_eff_secstate(env, is_secure); - if (hcr & HCR_DC) { - /* - * HCR.DC forces the first stage attributes to - * Normal Non-Shareable, - * Inner Write-Back Read-Allocate Write-Allocate, - * Outer Write-Back Read-Allocate Write-Allocate. - * Do not overwrite Tagged within attrs. - */ - if (cacheattrs1.attrs != 0xf0) { - cacheattrs1.attrs = 0xff; - } - cacheattrs1.shareability = 0; - } - result->cacheattrs = combine_cacheattrs(hcr, cacheattrs1, - result->cacheattrs); + /* + * Check if IPA translates to secure or non-secure PA space. + * Note that VSTCR overrides VTCR and {N}SW overrides {N}SA. + */ + result->f.attrs.secure = + (is_secure + && !(env->cp15.vstcr_el2 & (VSTCR_SA | VSTCR_SW)) + && (ipa_secure + || !(env->cp15.vtcr_el2 & (VTCR_NSA | VTCR_NSW)))); - /* - * Check if IPA translates to secure or non-secure PA space. - * Note that VSTCR overrides VTCR and {N}SW overrides {N}SA. - */ - result->f.attrs.secure = - (is_secure - && !(env->cp15.vstcr_el2 & (VSTCR_SA | VSTCR_SW)) - && (ipa_secure - || !(env->cp15.vtcr_el2 & (VTCR_NSA | VTCR_NSW)))); + return false; +} - return 0; - } else { - /* - * For non-EL2 CPUs a stage1+stage2 translation is just stage 1. - */ - mmu_idx = stage_1_mmu_idx(mmu_idx); +static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, + target_ulong address, + MMUAccessType access_type, + GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) +{ + ARMMMUIdx mmu_idx = ptw->in_mmu_idx; + ARMMMUIdx s1_mmu_idx = stage_1_mmu_idx(mmu_idx); + bool is_secure = ptw->in_secure; + + if (mmu_idx != s1_mmu_idx) { + /* + * Call ourselves recursively to do the stage 1 and then stage 2 + * translations if mmu_idx is a two-stage regime, and EL2 present. + * Otherwise, a stage1+stage2 translation is just stage 1. + */ + ptw->in_mmu_idx = mmu_idx = s1_mmu_idx; + if (arm_feature(env, ARM_FEATURE_EL2)) { + return get_phys_addr_twostage(env, ptw, address, access_type, + result, fi); } } @@ -2503,18 +2602,30 @@ bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address, return get_phys_addr_disabled(env, address, access_type, mmu_idx, is_secure, result, fi); } + if (regime_using_lpae_format(env, mmu_idx)) { - return get_phys_addr_lpae(env, address, access_type, mmu_idx, - is_secure, false, result, fi); + return get_phys_addr_lpae(env, ptw, address, access_type, false, + result, fi); } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) { - return get_phys_addr_v6(env, address, access_type, mmu_idx, - is_secure, result, fi); + return get_phys_addr_v6(env, ptw, address, access_type, result, fi); } else { - return get_phys_addr_v5(env, address, access_type, mmu_idx, - is_secure, result, fi); + return get_phys_addr_v5(env, ptw, address, access_type, result, fi); } } +bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool is_secure, GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) +{ + S1Translate ptw = { + .in_mmu_idx = mmu_idx, + .in_secure = is_secure, + }; + return get_phys_addr_with_struct(env, &ptw, address, access_type, + result, fi); +} + bool get_phys_addr(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, GetPhysAddrResult *result, ARMMMUFaultInfo *fi) @@ -2535,6 +2646,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, is_secure = arm_is_secure_below_el3(env); break; case ARMMMUIdx_Stage2: + case ARMMMUIdx_Phys_NS: case ARMMMUIdx_MPrivNegPri: case ARMMMUIdx_MUserNegPri: case ARMMMUIdx_MPriv: @@ -2543,6 +2655,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, break; case ARMMMUIdx_E3: case ARMMMUIdx_Stage2_S: + case ARMMMUIdx_Phys_S: case ARMMMUIdx_MSPrivNegPri: case ARMMMUIdx_MSUserNegPri: case ARMMMUIdx_MSPriv: @@ -2561,12 +2674,16 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; + S1Translate ptw = { + .in_mmu_idx = arm_mmu_idx(env), + .in_secure = arm_is_secure(env), + .in_debug = true, + }; GetPhysAddrResult res = {}; ARMMMUFaultInfo fi = {}; - ARMMMUIdx mmu_idx = arm_mmu_idx(env); bool ret; - ret = get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &res, &fi); + ret = get_phys_addr_with_struct(env, &ptw, addr, MMU_DATA_LOAD, &res, &fi); *attrs = res.f.attrs; if (ret) { |