diff options
Diffstat (limited to 'target-arm/helper.c')
-rw-r--r-- | target-arm/helper.c | 189 |
1 files changed, 149 insertions, 40 deletions
diff --git a/target-arm/helper.c b/target-arm/helper.c index 85753e4..a225224 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -91,12 +91,17 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_VFP3); set_feature(env, ARM_FEATURE_NEON); + set_feature(env, ARM_FEATURE_THUMB2EE); env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0; env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222; env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100; memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t)); memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t)); - env->cp15.c0_cachetype = 0x1dd20d2; + env->cp15.c0_cachetype = 0x82048004; + env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3; + env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */ + env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */ + env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */ break; case ARM_CPUID_CORTEXM3: set_feature(env, ARM_FEATURE_V6); @@ -113,6 +118,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_VFP3); set_feature(env, ARM_FEATURE_NEON); + set_feature(env, ARM_FEATURE_THUMB2EE); set_feature(env, ARM_FEATURE_DIV); break; case ARM_CPUID_TI915T: @@ -156,6 +162,12 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) void cpu_reset(CPUARMState *env) { uint32_t id; + + if (qemu_loglevel_mask(CPU_LOG_RESET)) { + qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + log_cpu_state(env, 0); + } + id = env->cp15.c0_cpuid; memset(env, 0, offsetof(CPUARMState, breakpoints)); if (id) @@ -171,11 +183,64 @@ void cpu_reset(CPUARMState *env) if (IS_M(env)) env->uncached_cpsr &= ~CPSR_I; env->vfp.xregs[ARM_VFP_FPEXC] = 0; + env->cp15.c2_base_mask = 0xffffc000u; #endif env->regs[15] = 0; tlb_flush(env, 1); } +static int vfp_gdb_get_reg(CPUState *env, uint8_t *buf, int reg) +{ + int nregs; + + /* VFP data registers are always little-endian. */ + nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16; + if (reg < nregs) { + stfq_le_p(buf, env->vfp.regs[reg]); + return 8; + } + if (arm_feature(env, ARM_FEATURE_NEON)) { + /* Aliases for Q regs. */ + nregs += 16; + if (reg < nregs) { + stfq_le_p(buf, env->vfp.regs[(reg - 32) * 2]); + stfq_le_p(buf + 8, env->vfp.regs[(reg - 32) * 2 + 1]); + return 16; + } + } + switch (reg - nregs) { + case 0: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSID]); return 4; + case 1: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSCR]); return 4; + case 2: stl_p(buf, env->vfp.xregs[ARM_VFP_FPEXC]); return 4; + } + return 0; +} + +static int vfp_gdb_set_reg(CPUState *env, uint8_t *buf, int reg) +{ + int nregs; + + nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16; + if (reg < nregs) { + env->vfp.regs[reg] = ldfq_le_p(buf); + return 8; + } + if (arm_feature(env, ARM_FEATURE_NEON)) { + nregs += 16; + if (reg < nregs) { + env->vfp.regs[(reg - 32) * 2] = ldfq_le_p(buf); + env->vfp.regs[(reg - 32) * 2 + 1] = ldfq_le_p(buf + 8); + return 16; + } + } + switch (reg - nregs) { + case 0: env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf); return 4; + case 1: env->vfp.xregs[ARM_VFP_FPSCR] = ldl_p(buf); return 4; + case 2: env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf); return 4; + } + return 0; +} + CPUARMState *cpu_arm_init(const char *cpu_model) { CPUARMState *env; @@ -186,8 +251,6 @@ CPUARMState *cpu_arm_init(const char *cpu_model) if (id == 0) return NULL; env = qemu_mallocz(sizeof(CPUARMState)); - if (!env) - return NULL; cpu_exec_init(env); if (!inited) { inited = 1; @@ -197,6 +260,17 @@ CPUARMState *cpu_arm_init(const char *cpu_model) env->cpu_model_str = cpu_model; env->cp15.c0_cpuid = id; cpu_reset(env); + if (arm_feature(env, ARM_FEATURE_NEON)) { + gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, + 51, "arm-neon.xml", 0); + } else if (arm_feature(env, ARM_FEATURE_VFP3)) { + gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, + 35, "arm-vfp3.xml", 0); + } else if (arm_feature(env, ARM_FEATURE_VFP)) { + gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, + 19, "arm-vfp.xml", 0); + } + qemu_init_vcpu(env); return env; } @@ -396,8 +470,6 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, static void allocate_mmon_state(CPUState *env) { env->mmon_entry = malloc(sizeof (mmon_state)); - if (!env->mmon_entry) - abort(); memset (env->mmon_entry, 0, sizeof (mmon_state)); env->mmon_entry->cpu_env = env; mmon_head = env->mmon_entry; @@ -622,7 +694,7 @@ static void do_v7m_exception_exit(CPUARMState *env) pointer. */ } -void do_interrupt_v7m(CPUARMState *env) +static void do_interrupt_v7m(CPUARMState *env) { uint32_t xpsr = xpsr_read(env); uint32_t lr; @@ -846,17 +918,34 @@ static inline int check_ap(CPUState *env, int ap, int domain, int access_type, return PAGE_READ | PAGE_WRITE; case 3: return PAGE_READ | PAGE_WRITE; - case 4: case 7: /* Reserved. */ + case 4: /* Reserved. */ return 0; case 5: return is_user ? 0 : prot_ro; case 6: return prot_ro; + case 7: + if (!arm_feature (env, ARM_FEATURE_V7)) + return 0; + return prot_ro; default: abort(); } } +static uint32_t get_level1_table_address(CPUState *env, uint32_t address) +{ + uint32_t table; + + if (address & env->cp15.c2_mask) + table = env->cp15.c2_base1 & 0xffffc000; + else + table = env->cp15.c2_base0 & env->cp15.c2_base_mask; + + table |= (address >> 18) & 0x3ffc; + return table; +} + static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type, int is_user, uint32_t *phys_ptr, int *prot) { @@ -870,11 +959,7 @@ static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type, /* Pagetable walk. */ /* Lookup l1 descriptor. */ - if (address & env->cp15.c2_mask) - table = env->cp15.c2_base1; - else - table = env->cp15.c2_base0; - table = (table & 0xffffc000) | ((address >> 18) & 0x3ffc); + table = get_level1_table_address(env, address); desc = ldl_phys(table); type = (desc & 3); domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; @@ -962,11 +1047,7 @@ static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type, /* Pagetable walk. */ /* Lookup l1 descriptor. */ - if (address & env->cp15.c2_mask) - table = env->cp15.c2_base1; - else - table = env->cp15.c2_base0; - table = (table & 0xffffc000) | ((address >> 18) & 0x3ffc); + table = get_level1_table_address(env, address); desc = ldl_phys(table); type = (desc & 3); if (type == 0) { @@ -1026,6 +1107,12 @@ static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type, if (xn && access_type == 2) goto do_fault; + /* 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; + } *prot = check_ap(env, ap, domain, access_type, is_user); if (!*prot) { /* Access permission fault. */ @@ -1250,15 +1337,16 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) 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; + if (arm_feature(env, ARM_FEATURE_V7) + && op1 == 2 && crm == 0 && op2 == 0) { + env->cp15.c0_cssel = val & 0xf; + break; + } goto bad_reg; case 1: /* System configuration. */ if (arm_feature(env, ARM_FEATURE_OMAPCP)) @@ -1281,9 +1369,11 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) 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); + if (env->cp15.c1_coproc != val) { + env->cp15.c1_coproc = val; + /* ??? Is this safe when called from within a TB? */ + tb_flush(env); + } break; default: goto bad_reg; @@ -1310,7 +1400,10 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) env->cp15.c2_base1 = val; break; case 2: + val &= 7; + env->cp15.c2_control = val; env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val); + env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> val); break; default: goto bad_reg; @@ -1572,9 +1665,22 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) goto bad_reg; if (crm != 0) goto bad_reg; - if (arm_feature(env, ARM_FEATURE_XSCALE)) + if (!arm_feature(env, ARM_FEATURE_V7)) + return 0; + + switch (op2) { + case 0: + return env->cp15.c0_ccsid[env->cp15.c0_cssel]; + case 1: + return env->cp15.c0_clid; + case 7: + return 0; + } + goto bad_reg; + case 2: + if (op2 != 0 || crm != 0) goto bad_reg; - return 0; + return env->cp15.c0_cssel; default: goto bad_reg; } @@ -1598,7 +1704,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) case ARM_CPUID_ARM11MPCORE: return 1; case ARM_CPUID_CORTEXA8: - return 0; + return 2; default: goto bad_reg; } @@ -1628,17 +1734,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) case 1: return env->cp15.c2_base1; case 2: - { - int n; - uint32_t mask; - n = 0; - mask = env->cp15.c2_mask; - while (mask) { - n++; - mask <<= 1; - } - return n; - } + return env->cp15.c2_control; default: goto bad_reg; } @@ -2250,10 +2346,13 @@ void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val) } set_float_rounding_mode(i, &env->vfp.fp_status); } + if (changed & (1 << 24)) + set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status); + if (changed & (1 << 25)) + set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status); i = vfp_exceptbits_to_host((val >> 8) & 0x1f); set_float_exception_flags(i, &env->vfp.fp_status); - /* XXX: FZ and DN are not implemented. */ } #define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p)) @@ -2458,7 +2557,7 @@ ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \ ftype tmp; \ tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(x), \ &env->vfp.fp_status); \ - return ftype##_scalbn(tmp, shift, &env->vfp.fp_status); \ + return ftype##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \ } \ ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \ { \ @@ -2560,3 +2659,13 @@ void HELPER(traceBB64)(uint64_t bb_num, uint64_t tb) #endif #endif /* CONFIG_TRACE */ + +void HELPER(set_teecr)(CPUState *env, uint32_t val) +{ + val &= 1; + if (env->teecr != val) { + env->teecr = val; + tb_flush(env); + } +} + |