1e21b551cSPhilippe Mathieu-Daudé /* 2e21b551cSPhilippe Mathieu-Daudé * ARM TLB (Translation lookaside buffer) helpers. 3e21b551cSPhilippe Mathieu-Daudé * 4e21b551cSPhilippe Mathieu-Daudé * This code is licensed under the GNU GPL v2 or later. 5e21b551cSPhilippe Mathieu-Daudé * 6e21b551cSPhilippe Mathieu-Daudé * SPDX-License-Identifier: GPL-2.0-or-later 7e21b551cSPhilippe Mathieu-Daudé */ 8e21b551cSPhilippe Mathieu-Daudé #include "qemu/osdep.h" 9e21b551cSPhilippe Mathieu-Daudé #include "cpu.h" 10e21b551cSPhilippe Mathieu-Daudé #include "internals.h" 11e21b551cSPhilippe Mathieu-Daudé #include "exec/exec-all.h" 12e21b551cSPhilippe Mathieu-Daudé 13e21b551cSPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY) 14e21b551cSPhilippe Mathieu-Daudé 15e21b551cSPhilippe Mathieu-Daudé static inline uint32_t merge_syn_data_abort(uint32_t template_syn, 16e21b551cSPhilippe Mathieu-Daudé unsigned int target_el, 17e21b551cSPhilippe Mathieu-Daudé bool same_el, bool ea, 18e21b551cSPhilippe Mathieu-Daudé bool s1ptw, bool is_write, 19e21b551cSPhilippe Mathieu-Daudé int fsc) 20e21b551cSPhilippe Mathieu-Daudé { 21e21b551cSPhilippe Mathieu-Daudé uint32_t syn; 22e21b551cSPhilippe Mathieu-Daudé 23e21b551cSPhilippe Mathieu-Daudé /* 24e21b551cSPhilippe Mathieu-Daudé * ISV is only set for data aborts routed to EL2 and 25e21b551cSPhilippe Mathieu-Daudé * never for stage-1 page table walks faulting on stage 2. 26e21b551cSPhilippe Mathieu-Daudé * 27e21b551cSPhilippe Mathieu-Daudé * Furthermore, ISV is only set for certain kinds of load/stores. 28e21b551cSPhilippe Mathieu-Daudé * If the template syndrome does not have ISV set, we should leave 29e21b551cSPhilippe Mathieu-Daudé * it cleared. 30e21b551cSPhilippe Mathieu-Daudé * 31e21b551cSPhilippe Mathieu-Daudé * See ARMv8 specs, D7-1974: 32e21b551cSPhilippe Mathieu-Daudé * ISS encoding for an exception from a Data Abort, the 33e21b551cSPhilippe Mathieu-Daudé * ISV field. 34e21b551cSPhilippe Mathieu-Daudé */ 35e21b551cSPhilippe Mathieu-Daudé if (!(template_syn & ARM_EL_ISV) || target_el != 2 || s1ptw) { 36*e24fd076SDongjiu Geng syn = syn_data_abort_no_iss(same_el, 0, 37e21b551cSPhilippe Mathieu-Daudé ea, 0, s1ptw, is_write, fsc); 38e21b551cSPhilippe Mathieu-Daudé } else { 39e21b551cSPhilippe Mathieu-Daudé /* 40e21b551cSPhilippe Mathieu-Daudé * Fields: IL, ISV, SAS, SSE, SRT, SF and AR come from the template 41e21b551cSPhilippe Mathieu-Daudé * syndrome created at translation time. 42e21b551cSPhilippe Mathieu-Daudé * Now we create the runtime syndrome with the remaining fields. 43e21b551cSPhilippe Mathieu-Daudé */ 44e21b551cSPhilippe Mathieu-Daudé syn = syn_data_abort_with_iss(same_el, 45e21b551cSPhilippe Mathieu-Daudé 0, 0, 0, 0, 0, 46e21b551cSPhilippe Mathieu-Daudé ea, 0, s1ptw, is_write, fsc, 4730d54483SJeff Kubascik true); 48e21b551cSPhilippe Mathieu-Daudé /* Merge the runtime syndrome with the template syndrome. */ 49e21b551cSPhilippe Mathieu-Daudé syn |= template_syn; 50e21b551cSPhilippe Mathieu-Daudé } 51e21b551cSPhilippe Mathieu-Daudé return syn; 52e21b551cSPhilippe Mathieu-Daudé } 53e21b551cSPhilippe Mathieu-Daudé 54e21b551cSPhilippe Mathieu-Daudé static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr, 55e21b551cSPhilippe Mathieu-Daudé MMUAccessType access_type, 56e21b551cSPhilippe Mathieu-Daudé int mmu_idx, ARMMMUFaultInfo *fi) 57e21b551cSPhilippe Mathieu-Daudé { 58e21b551cSPhilippe Mathieu-Daudé CPUARMState *env = &cpu->env; 59e21b551cSPhilippe Mathieu-Daudé int target_el; 60e21b551cSPhilippe Mathieu-Daudé bool same_el; 61e21b551cSPhilippe Mathieu-Daudé uint32_t syn, exc, fsr, fsc; 62e21b551cSPhilippe Mathieu-Daudé ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx); 63e21b551cSPhilippe Mathieu-Daudé 64e21b551cSPhilippe Mathieu-Daudé target_el = exception_target_el(env); 65e21b551cSPhilippe Mathieu-Daudé if (fi->stage2) { 66e21b551cSPhilippe Mathieu-Daudé target_el = 2; 67e21b551cSPhilippe Mathieu-Daudé env->cp15.hpfar_el2 = extract64(fi->s2addr, 12, 47) << 4; 68e21b551cSPhilippe Mathieu-Daudé } 69e21b551cSPhilippe Mathieu-Daudé same_el = (arm_current_el(env) == target_el); 70e21b551cSPhilippe Mathieu-Daudé 71e21b551cSPhilippe Mathieu-Daudé if (target_el == 2 || arm_el_is_aa64(env, target_el) || 72e21b551cSPhilippe Mathieu-Daudé arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) { 73e21b551cSPhilippe Mathieu-Daudé /* 74e21b551cSPhilippe Mathieu-Daudé * LPAE format fault status register : bottom 6 bits are 75e21b551cSPhilippe Mathieu-Daudé * status code in the same form as needed for syndrome 76e21b551cSPhilippe Mathieu-Daudé */ 77e21b551cSPhilippe Mathieu-Daudé fsr = arm_fi_to_lfsc(fi); 78e21b551cSPhilippe Mathieu-Daudé fsc = extract32(fsr, 0, 6); 79e21b551cSPhilippe Mathieu-Daudé } else { 80e21b551cSPhilippe Mathieu-Daudé fsr = arm_fi_to_sfsc(fi); 81e21b551cSPhilippe Mathieu-Daudé /* 82e21b551cSPhilippe Mathieu-Daudé * Short format FSR : this fault will never actually be reported 83e21b551cSPhilippe Mathieu-Daudé * to an EL that uses a syndrome register. Use a (currently) 84e21b551cSPhilippe Mathieu-Daudé * reserved FSR code in case the constructed syndrome does leak 85e21b551cSPhilippe Mathieu-Daudé * into the guest somehow. 86e21b551cSPhilippe Mathieu-Daudé */ 87e21b551cSPhilippe Mathieu-Daudé fsc = 0x3f; 88e21b551cSPhilippe Mathieu-Daudé } 89e21b551cSPhilippe Mathieu-Daudé 90e21b551cSPhilippe Mathieu-Daudé if (access_type == MMU_INST_FETCH) { 91e21b551cSPhilippe Mathieu-Daudé syn = syn_insn_abort(same_el, fi->ea, fi->s1ptw, fsc); 92e21b551cSPhilippe Mathieu-Daudé exc = EXCP_PREFETCH_ABORT; 93e21b551cSPhilippe Mathieu-Daudé } else { 94e21b551cSPhilippe Mathieu-Daudé syn = merge_syn_data_abort(env->exception.syndrome, target_el, 95e21b551cSPhilippe Mathieu-Daudé same_el, fi->ea, fi->s1ptw, 96e21b551cSPhilippe Mathieu-Daudé access_type == MMU_DATA_STORE, 97e21b551cSPhilippe Mathieu-Daudé fsc); 98e21b551cSPhilippe Mathieu-Daudé if (access_type == MMU_DATA_STORE 99e21b551cSPhilippe Mathieu-Daudé && arm_feature(env, ARM_FEATURE_V6)) { 100e21b551cSPhilippe Mathieu-Daudé fsr |= (1 << 11); 101e21b551cSPhilippe Mathieu-Daudé } 102e21b551cSPhilippe Mathieu-Daudé exc = EXCP_DATA_ABORT; 103e21b551cSPhilippe Mathieu-Daudé } 104e21b551cSPhilippe Mathieu-Daudé 105e21b551cSPhilippe Mathieu-Daudé env->exception.vaddress = addr; 106e21b551cSPhilippe Mathieu-Daudé env->exception.fsr = fsr; 107e21b551cSPhilippe Mathieu-Daudé raise_exception(env, exc, syn, target_el); 108e21b551cSPhilippe Mathieu-Daudé } 109e21b551cSPhilippe Mathieu-Daudé 110e21b551cSPhilippe Mathieu-Daudé /* Raise a data fault alignment exception for the specified virtual address */ 111e21b551cSPhilippe Mathieu-Daudé void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, 112e21b551cSPhilippe Mathieu-Daudé MMUAccessType access_type, 113e21b551cSPhilippe Mathieu-Daudé int mmu_idx, uintptr_t retaddr) 114e21b551cSPhilippe Mathieu-Daudé { 115e21b551cSPhilippe Mathieu-Daudé ARMCPU *cpu = ARM_CPU(cs); 116e21b551cSPhilippe Mathieu-Daudé ARMMMUFaultInfo fi = {}; 117e21b551cSPhilippe Mathieu-Daudé 118e21b551cSPhilippe Mathieu-Daudé /* now we have a real cpu fault */ 119e21b551cSPhilippe Mathieu-Daudé cpu_restore_state(cs, retaddr, true); 120e21b551cSPhilippe Mathieu-Daudé 121e21b551cSPhilippe Mathieu-Daudé fi.type = ARMFault_Alignment; 122e21b551cSPhilippe Mathieu-Daudé arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi); 123e21b551cSPhilippe Mathieu-Daudé } 124e21b551cSPhilippe Mathieu-Daudé 125e21b551cSPhilippe Mathieu-Daudé /* 126e21b551cSPhilippe Mathieu-Daudé * arm_cpu_do_transaction_failed: handle a memory system error response 127e21b551cSPhilippe Mathieu-Daudé * (eg "no device/memory present at address") by raising an external abort 128e21b551cSPhilippe Mathieu-Daudé * exception 129e21b551cSPhilippe Mathieu-Daudé */ 130e21b551cSPhilippe Mathieu-Daudé void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, 131e21b551cSPhilippe Mathieu-Daudé vaddr addr, unsigned size, 132e21b551cSPhilippe Mathieu-Daudé MMUAccessType access_type, 133e21b551cSPhilippe Mathieu-Daudé int mmu_idx, MemTxAttrs attrs, 134e21b551cSPhilippe Mathieu-Daudé MemTxResult response, uintptr_t retaddr) 135e21b551cSPhilippe Mathieu-Daudé { 136e21b551cSPhilippe Mathieu-Daudé ARMCPU *cpu = ARM_CPU(cs); 137e21b551cSPhilippe Mathieu-Daudé ARMMMUFaultInfo fi = {}; 138e21b551cSPhilippe Mathieu-Daudé 139e21b551cSPhilippe Mathieu-Daudé /* now we have a real cpu fault */ 140e21b551cSPhilippe Mathieu-Daudé cpu_restore_state(cs, retaddr, true); 141e21b551cSPhilippe Mathieu-Daudé 142e21b551cSPhilippe Mathieu-Daudé fi.ea = arm_extabort_type(response); 143e21b551cSPhilippe Mathieu-Daudé fi.type = ARMFault_SyncExternal; 144e21b551cSPhilippe Mathieu-Daudé arm_deliver_fault(cpu, addr, access_type, mmu_idx, &fi); 145e21b551cSPhilippe Mathieu-Daudé } 146e21b551cSPhilippe Mathieu-Daudé 147e21b551cSPhilippe Mathieu-Daudé #endif /* !defined(CONFIG_USER_ONLY) */ 148e21b551cSPhilippe Mathieu-Daudé 149e21b551cSPhilippe Mathieu-Daudé bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 150e21b551cSPhilippe Mathieu-Daudé MMUAccessType access_type, int mmu_idx, 151e21b551cSPhilippe Mathieu-Daudé bool probe, uintptr_t retaddr) 152e21b551cSPhilippe Mathieu-Daudé { 153e21b551cSPhilippe Mathieu-Daudé ARMCPU *cpu = ARM_CPU(cs); 154e21b551cSPhilippe Mathieu-Daudé 155e21b551cSPhilippe Mathieu-Daudé #ifdef CONFIG_USER_ONLY 156e21b551cSPhilippe Mathieu-Daudé cpu->env.exception.vaddress = address; 157e21b551cSPhilippe Mathieu-Daudé if (access_type == MMU_INST_FETCH) { 158e21b551cSPhilippe Mathieu-Daudé cs->exception_index = EXCP_PREFETCH_ABORT; 159e21b551cSPhilippe Mathieu-Daudé } else { 160e21b551cSPhilippe Mathieu-Daudé cs->exception_index = EXCP_DATA_ABORT; 161e21b551cSPhilippe Mathieu-Daudé } 162e21b551cSPhilippe Mathieu-Daudé cpu_loop_exit_restore(cs, retaddr); 163e21b551cSPhilippe Mathieu-Daudé #else 164e21b551cSPhilippe Mathieu-Daudé hwaddr phys_addr; 165e21b551cSPhilippe Mathieu-Daudé target_ulong page_size; 166e21b551cSPhilippe Mathieu-Daudé int prot, ret; 167e21b551cSPhilippe Mathieu-Daudé MemTxAttrs attrs = {}; 168e21b551cSPhilippe Mathieu-Daudé ARMMMUFaultInfo fi = {}; 169e21b551cSPhilippe Mathieu-Daudé 170e21b551cSPhilippe Mathieu-Daudé /* 171e21b551cSPhilippe Mathieu-Daudé * Walk the page table and (if the mapping exists) add the page 172e21b551cSPhilippe Mathieu-Daudé * to the TLB. On success, return true. Otherwise, if probing, 173e21b551cSPhilippe Mathieu-Daudé * return false. Otherwise populate fsr with ARM DFSR/IFSR fault 174e21b551cSPhilippe Mathieu-Daudé * register format, and signal the fault. 175e21b551cSPhilippe Mathieu-Daudé */ 176e21b551cSPhilippe Mathieu-Daudé ret = get_phys_addr(&cpu->env, address, access_type, 177e21b551cSPhilippe Mathieu-Daudé core_to_arm_mmu_idx(&cpu->env, mmu_idx), 178e21b551cSPhilippe Mathieu-Daudé &phys_addr, &attrs, &prot, &page_size, &fi, NULL); 179e21b551cSPhilippe Mathieu-Daudé if (likely(!ret)) { 180e21b551cSPhilippe Mathieu-Daudé /* 181e21b551cSPhilippe Mathieu-Daudé * Map a single [sub]page. Regions smaller than our declared 182e21b551cSPhilippe Mathieu-Daudé * target page size are handled specially, so for those we 183e21b551cSPhilippe Mathieu-Daudé * pass in the exact addresses. 184e21b551cSPhilippe Mathieu-Daudé */ 185e21b551cSPhilippe Mathieu-Daudé if (page_size >= TARGET_PAGE_SIZE) { 186e21b551cSPhilippe Mathieu-Daudé phys_addr &= TARGET_PAGE_MASK; 187e21b551cSPhilippe Mathieu-Daudé address &= TARGET_PAGE_MASK; 188e21b551cSPhilippe Mathieu-Daudé } 189e21b551cSPhilippe Mathieu-Daudé tlb_set_page_with_attrs(cs, address, phys_addr, attrs, 190e21b551cSPhilippe Mathieu-Daudé prot, mmu_idx, page_size); 191e21b551cSPhilippe Mathieu-Daudé return true; 192e21b551cSPhilippe Mathieu-Daudé } else if (probe) { 193e21b551cSPhilippe Mathieu-Daudé return false; 194e21b551cSPhilippe Mathieu-Daudé } else { 195e21b551cSPhilippe Mathieu-Daudé /* now we have a real cpu fault */ 196e21b551cSPhilippe Mathieu-Daudé cpu_restore_state(cs, retaddr, true); 197e21b551cSPhilippe Mathieu-Daudé arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi); 198e21b551cSPhilippe Mathieu-Daudé } 199e21b551cSPhilippe Mathieu-Daudé #endif 200e21b551cSPhilippe Mathieu-Daudé } 201