📄 helper.c.svn-base
字号:
code = 9; /* Section domain fault. */ else code = 11; /* Page domain fault. */ goto do_fault; } if (type == 2) { if (desc & (1 << 18)) { /* Supersection. */ phys_addr = (desc & 0xff000000) | (address & 0x00ffffff); } else { /* Section. */ phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); } ap = ((desc >> 10) & 3) | ((desc >> 13) & 4); xn = desc & (1 << 4); code = 13; } else { /* Lookup l2 entry. */ table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); desc = ldl_phys(table); ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); switch (desc & 3) { case 0: /* Page translation fault. */ code = 7; goto do_fault; case 1: /* 64k page. */ phys_addr = (desc & 0xffff0000) | (address & 0xffff); xn = desc & (1 << 15); break; case 2: case 3: /* 4k page. */ phys_addr = (desc & 0xfffff000) | (address & 0xfff); xn = desc & 1; break; default: /* Never happens, but compiler isn't smart enough to tell. */ abort(); } code = 15; } if (xn && access_type == 2) goto do_fault; *prot = check_ap(env, ap, domain, access_type, is_user); if (!*prot) { /* Access permission fault. */ goto do_fault; } *phys_ptr = phys_addr; return 0;do_fault: return code | (domain << 4);}static int get_phys_addr_mpu(CPUState *env, uint32_t address, int access_type, int is_user, uint32_t *phys_ptr, int *prot){ int n; uint32_t mask; uint32_t base; *phys_ptr = address; for (n = 7; n >= 0; n--) { base = env->cp15.c6_region[n]; if ((base & 1) == 0) continue; mask = 1 << ((base >> 1) & 0x1f); /* Keep this shift separate from the above to avoid an (undefined) << 32. */ mask = (mask << 1) - 1; if (((base ^ address) & ~mask) == 0) break; } if (n < 0) return 2; if (access_type == 2) { mask = env->cp15.c5_insn; } else { mask = env->cp15.c5_data; } mask = (mask >> (n * 4)) & 0xf; switch (mask) { case 0: return 1; case 1: if (is_user) return 1; *prot = PAGE_READ | PAGE_WRITE; break; case 2: *prot = PAGE_READ; if (!is_user) *prot |= PAGE_WRITE; break; case 3: *prot = PAGE_READ | PAGE_WRITE; break; case 5: if (is_user) return 1; *prot = PAGE_READ; break; case 6: *prot = PAGE_READ; break; default: /* Bad permission. */ return 1; } return 0;}static inline int get_phys_addr(CPUState *env, uint32_t address, int access_type, int is_user, uint32_t *phys_ptr, int *prot){ /* Fast Context Switch Extension. */ if (address < 0x02000000) address += env->cp15.c13_fcse; if ((env->cp15.c1_sys & 1) == 0) { /* MMU/MPU disabled. */ *phys_ptr = address; *prot = PAGE_READ | PAGE_WRITE; return 0; } else if (arm_feature(env, ARM_FEATURE_MPU)) { return get_phys_addr_mpu(env, address, access_type, is_user, phys_ptr, prot); } else if (env->cp15.c1_sys & (1 << 23)) { return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr, prot); } else { return get_phys_addr_v5(env, address, access_type, is_user, phys_ptr, prot); }}int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int access_type, int mmu_idx, int is_softmmu){ uint32_t phys_addr; int prot; int ret, is_user; is_user = mmu_idx == MMU_USER_IDX; ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot); if (ret == 0) { /* Map a single [sub]page. */ phys_addr &= ~(uint32_t)0x3ff; address &= ~(uint32_t)0x3ff; return tlb_set_page (env, address, phys_addr, prot, mmu_idx, is_softmmu); } if (access_type == 2) { env->cp15.c5_insn = ret; env->cp15.c6_insn = address; env->exception_index = EXCP_PREFETCH_ABORT; } else { env->cp15.c5_data = ret; if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6)) env->cp15.c5_data |= (1 << 11); env->cp15.c6_data = address; env->exception_index = EXCP_DATA_ABORT; } return 1;}target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr){ uint32_t phys_addr; int prot; int ret; ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot); if (ret != 0) return -1; return phys_addr;}/* Not really implemented. Need to figure out a sane way of doing this. Maybe add generic watchpoint support and use that. */void helper_mark_exclusive(CPUState *env, uint32_t addr){ env->mmon_addr = addr;}int helper_test_exclusive(CPUState *env, uint32_t addr){ return (env->mmon_addr != addr);}void helper_clrex(CPUState *env){ env->mmon_addr = -1;}void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val){ int cp_num = (insn >> 8) & 0xf; int cp_info = (insn >> 5) & 7; int src = (insn >> 16) & 0xf; int operand = insn & 0xf; if (env->cp[cp_num].cp_write) env->cp[cp_num].cp_write(env->cp[cp_num].opaque, cp_info, src, operand, val);}uint32_t helper_get_cp(CPUState *env, uint32_t insn){ int cp_num = (insn >> 8) & 0xf; int cp_info = (insn >> 5) & 7; int dest = (insn >> 16) & 0xf; int operand = insn & 0xf; if (env->cp[cp_num].cp_read) return env->cp[cp_num].cp_read(env->cp[cp_num].opaque, cp_info, dest, operand); return 0;}/* Return basic MPU access permission bits. */static uint32_t simple_mpu_ap_bits(uint32_t val){ uint32_t ret; uint32_t mask; int i; ret = 0; mask = 3; for (i = 0; i < 16; i += 2) { ret |= (val >> i) & mask; mask <<= 2; } return ret;}/* Pad basic MPU access permission bits to extended format. */static uint32_t extended_mpu_ap_bits(uint32_t val){ uint32_t ret; uint32_t mask; int i; ret = 0; mask = 3; for (i = 0; i < 16; i += 2) { ret |= (val & mask) << i; mask <<= 2; } return ret;}void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val){ int op1; int op2; int crm; op1 = (insn >> 21) & 7; op2 = (insn >> 5) & 7; crm = insn & 0xf; switch ((insn >> 16) & 0xf) { case 0: if (((insn >> 21) & 7) == 2) { /* ??? Select cache level. Ignore. */ return; } /* ID codes. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) break; if (arm_feature(env, ARM_FEATURE_OMAPCP)) break; goto bad_reg; case 1: /* System configuration. */ if (arm_feature(env, ARM_FEATURE_OMAPCP)) op2 = 0; switch (op2) { case 0: if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0) env->cp15.c1_sys = val; /* ??? Lots of these bits are not implemented. */ /* This may enable/disable the MMU, so do a TLB flush. */ tlb_flush(env, 1); break; case 1: /* Auxiliary cotrol register. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { env->cp15.c1_xscaleauxcr = val; break; } /* Not implemented. */ break; case 2: if (arm_feature(env, ARM_FEATURE_XSCALE)) goto bad_reg; env->cp15.c1_coproc = val; /* ??? Is this safe when called from within a TB? */ tb_flush(env); break; default: goto bad_reg; } break; case 2: /* MMU Page table control / MPU cache control. */ if (arm_feature(env, ARM_FEATURE_MPU)) { switch (op2) { case 0: env->cp15.c2_data = val; break; case 1: env->cp15.c2_insn = val; break; default: goto bad_reg; } } else { switch (op2) { case 0: env->cp15.c2_base0 = val; break; case 1: env->cp15.c2_base1 = val; break; case 2: env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val); break; default: goto bad_reg; } } break; case 3: /* MMU Domain access control / MPU write buffer control. */ env->cp15.c3 = val; tlb_flush(env, 1); /* Flush TLB as domain not tracked in TLB */ break; case 4: /* Reserved. */ goto bad_reg; case 5: /* MMU Fault status / MPU access permission. */ if (arm_feature(env, ARM_FEATURE_OMAPCP)) op2 = 0; switch (op2) { case 0: if (arm_feature(env, ARM_FEATURE_MPU)) val = extended_mpu_ap_bits(val); env->cp15.c5_data = val; break; case 1: if (arm_feature(env, ARM_FEATURE_MPU)) val = extended_mpu_ap_bits(val); env->cp15.c5_insn = val; break; case 2: if (!arm_feature(env, ARM_FEATURE_MPU)) goto bad_reg; env->cp15.c5_data = val; break; case 3: if (!arm_feature(env, ARM_FEATURE_MPU)) goto bad_reg; env->cp15.c5_insn = val; break; default: goto bad_reg; } break; case 6: /* MMU Fault address / MPU base/size. */ if (arm_feature(env, ARM_FEATURE_MPU)) { if (crm >= 8) goto bad_reg; env->cp15.c6_region[crm] = val; } else { if (arm_feature(env, ARM_FEATURE_OMAPCP)) op2 = 0; switch (op2) { case 0: env->cp15.c6_data = val; break; case 1: /* ??? This is WFAR on armv6 */ case 2: env->cp15.c6_insn = val; break; default: goto bad_reg; } } break; case 7: /* Cache control. */ env->cp15.c15_i_max = 0x000; env->cp15.c15_i_min = 0xff0; /* No cache, so nothing to do. */ /* ??? MPCore has VA to PA translation functions. */ break; case 8: /* MMU TLB control. */ switch (op2) { case 0: /* Invalidate all. */ tlb_flush(env, 0); break; case 1: /* Invalidate single TLB entry. */#if 0 /* ??? This is wrong for large pages and sections. */ /* As an ugly hack to make linux work we always flush a 4K pages. */ val &= 0xfffff000; tlb_flush_page(env, val); tlb_flush_page(env, val + 0x400); tlb_flush_page(env, val + 0x800); tlb_flush_page(env, val + 0xc00);#else tlb_flush(env, 1);#endif break; case 2: /* Invalidate on ASID. */ tlb_flush(env, val == 0); break; case 3: /* Invalidate single entry on MVA. */ /* ??? This is like case 1, but ignores ASID. */ tlb_flush(env, 1); break; default: goto bad_reg; } break; case 9: if (arm_feature(env, ARM_FEATURE_OMAPCP)) break; switch (crm) { case 0: /* Cache lockdown. */ switch (op1) { case 0: /* L1 cache. */ switch (op2) { case 0: env->cp15.c9_data = val; break; case 1: env->cp15.c9_insn = val; break; default: goto bad_reg; } break; case 1: /* L2 cache. */ /* Ignore writes to L2 lockdown/auxiliary registers. */ break; default: goto bad_reg; } break; case 1: /* TCM memory region registers. */ /* Not implemented. */ goto bad_reg; default: goto bad_reg; } break; case 10: /* MMU TLB lockdown. */ /* ??? TLB lockdown not implemented. */ break; case 12: /* Reserved. */ goto bad_reg; case 13: /* Process ID. */ switch (op2) { case 0: /* Unlike real hardware the qemu TLB uses virtual addresses, not modified virtual addresses, so this causes a TLB flush.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -