From 0ab06d8347bd825090e220167da017d67112e846 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Thu, 23 Jun 2011 01:12:59 +0000 Subject: [PATCH 1/7] target-arm: make VMSAv7 remapping and AP dependent on V6K The VMSAv7 remapping and access permissions were introduced in ARMv6K and not ARMv7. Signed-off-by: Jamie Iles Signed-off-by: Peter Maydell --- target-arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index ae4f334e40..4b03197a18 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -948,7 +948,7 @@ static inline int check_ap(CPUState *env, int ap, int domain, int access_type, case 6: return prot_ro; case 7: - if (!arm_feature (env, ARM_FEATURE_V7)) + if (!arm_feature (env, ARM_FEATURE_V6K)) return 0; return prot_ro; default: From 7807eed932dbb88fa320ddba99bff45ba96319c6 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Wed, 20 Jul 2011 10:32:54 +0000 Subject: [PATCH 2/7] target-arm: support for ARM1176JZF-s cores Add support for v6K ARM1176JZF-S. This core includes the VA<->PA translation capability and security extensions. Signed-off-by: Jamie Iles Signed-off-by: Peter Maydell --- target-arm/cpu.h | 1 + target-arm/helper.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index adef42785c..8da3ff41ac 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -420,6 +420,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, #define ARM_CPUID_PXA270_C5 0x69054117 #define ARM_CPUID_ARM1136 0x4117b363 #define ARM_CPUID_ARM1136_R2 0x4107b362 +#define ARM_CPUID_ARM1176 0x410fb767 #define ARM_CPUID_ARM11MPCORE 0x410fb022 #define ARM_CPUID_CORTEXA8 0x410fc080 #define ARM_CPUID_CORTEXA9 0x410fc090 diff --git a/target-arm/helper.c b/target-arm/helper.c index 4b03197a18..3465776dbe 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -35,6 +35,12 @@ static uint32_t arm1136_cp15_c0_c1[8] = static uint32_t arm1136_cp15_c0_c2[8] = { 0x00140011, 0x12002111, 0x11231111, 0x01102131, 0x141, 0, 0, 0 }; +static uint32_t arm1176_cp15_c0_c1[8] = +{ 0x111, 0x11, 0x33, 0, 0x01130003, 0x10030302, 0x01222100, 0 }; + +static uint32_t arm1176_cp15_c0_c2[8] = +{ 0x0140011, 0x12002111, 0x11231121, 0x01102131, 0x01141, 0, 0, 0 }; + static uint32_t cpu_arm_find_by_name(const char *name); static inline void set_feature(CPUARMState *env, int feature) @@ -85,6 +91,21 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c0_cachetype = 0x1dd20d2; env->cp15.c1_sys = 0x00050078; break; + case ARM_CPUID_ARM1176: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_V6K); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_AUXCR); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b5; + env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111; + env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000; + memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c2, arm1176_cp15_c0_c2, 8 * sizeof(uint32_t)); + env->cp15.c0_cachetype = 0x1dd20d2; + env->cp15.c1_sys = 0x00050078; + break; case ARM_CPUID_ARM11MPCORE: set_feature(env, ARM_FEATURE_V4T); set_feature(env, ARM_FEATURE_V5); @@ -380,6 +401,7 @@ static const struct arm_cpu_t arm_cpu_names[] = { { ARM_CPUID_ARM1026, "arm1026"}, { ARM_CPUID_ARM1136, "arm1136"}, { ARM_CPUID_ARM1136_R2, "arm1136-r2"}, + { ARM_CPUID_ARM1176, "arm1176"}, { ARM_CPUID_ARM11MPCORE, "arm11mpcore"}, { ARM_CPUID_CORTEXM3, "cortex-m3"}, { ARM_CPUID_CORTEXA8, "cortex-a8"}, @@ -1848,6 +1870,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) return 1; case ARM_CPUID_ARM1136: case ARM_CPUID_ARM1136_R2: + case ARM_CPUID_ARM1176: return 7; case ARM_CPUID_ARM11MPCORE: return 1; From 906879a98fa31232f494fece3c5cb3c2baaf8c3c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jul 2011 10:32:55 +0000 Subject: [PATCH 3/7] target-arm: Mark 1136r1 as a v6K core The 1136r1 is actually a v6K core (unlike the 1136r0); mark it as such, thus enabling the TLS registers, NOP hints, CLREX, half and byte wide exclusive load/stores, etc. The VA-to-PA translation registers are not present on 1136r1, so introduce a new feature flag for them, which is enabled on 1176, 11MPCore and all v7 cores. Signed-off-by: Peter Maydell Reviewed-by: Jamie Iles --- target-arm/cpu.h | 1 + target-arm/helper.c | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 8da3ff41ac..c28f767051 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -374,6 +374,7 @@ enum arm_features { ARM_FEATURE_V4T, ARM_FEATURE_V5, ARM_FEATURE_STRONGARM, + ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */ }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target-arm/helper.c b/target-arm/helper.c index 3465776dbe..b4f699470a 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -76,13 +76,24 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c0_cachetype = 0x1dd20d2; env->cp15.c1_sys = 0x00090078; break; - case ARM_CPUID_ARM1136_R2: case ARM_CPUID_ARM1136: + /* This is the 1136 r1, which is a v6K core */ + set_feature(env, ARM_FEATURE_V6K); + /* Fall through */ + case ARM_CPUID_ARM1136_R2: + /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an + * older core than plain "arm1136". In particular this does not + * have the v6K features. + */ set_feature(env, ARM_FEATURE_V4T); set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_AUXCR); + /* These ID register values are correct for 1136 but may be wrong + * for 1136_r2 (in particular r0p2 does not actually implement most + * of the ID registers). + */ env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4; env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111; env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000; @@ -98,6 +109,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) set_feature(env, ARM_FEATURE_V6K); set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_AUXCR); + set_feature(env, ARM_FEATURE_VAPA); env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b5; env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111; env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000; @@ -113,6 +125,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) set_feature(env, ARM_FEATURE_V6K); set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_AUXCR); + set_feature(env, ARM_FEATURE_VAPA); env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4; env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111; env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000; @@ -243,6 +256,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) cpu_abort(env, "Bad CPU ID: %x\n", id); break; } + + /* Some features automatically imply others: */ + if (arm_feature(env, ARM_FEATURE_V7)) { + set_feature(env, ARM_FEATURE_VAPA); + } } void cpu_reset(CPUARMState *env) @@ -1524,7 +1542,7 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) goto bad_reg; } /* No cache, so nothing to do except VA->PA translations. */ - if (arm_feature(env, ARM_FEATURE_V6K)) { + if (arm_feature(env, ARM_FEATURE_VAPA)) { switch (crm) { case 4: if (arm_feature(env, ARM_FEATURE_V7)) { From 87f19eb2a5a3ffda5db4ab3bc0c326f2fcd3bcce Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 21 Jul 2011 07:01:51 +0000 Subject: [PATCH 4/7] target-arm: Support v6 barriers in linux-user mode ARMv6 implemented various operations as special cases of cp15 accesses which are true instructions in v7; this includes barriers (DMB, DSB, ISB). Catch this special case at translate time, so that it works in linux-user mode (which doesn't provide a functional get_cp15 helper) as well as system mode. Includes minor cleanup of the existing cases (single switch statement, and doing the "OK in user mode?" test explicitly rather than hiding it in cp15_user_ok()). Signed-off-by: Peter Maydell --- target-arm/translate.c | 51 +++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 34d5e6ef1a..c7961b8097 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2498,12 +2498,6 @@ static int cp15_user_ok(CPUState *env, uint32_t insn) if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT))) return 1; } - if (cpn == 7) { - /* ISB, DSB, DMB. */ - if ((cpm == 5 && op == 4) - || (cpm == 10 && (op == 4 || op == 5))) - return 1; - } return 0; } @@ -2579,39 +2573,60 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) /* cdp */ return 1; } - if (IS_USER(s) && !cp15_user_ok(env, insn)) { - return 1; - } - - /* Pre-v7 versions of the architecture implemented WFI via coprocessor - * instructions rather than a separate instruction. + /* We special case a number of cp15 instructions which were used + * for things which are real instructions in ARMv7. This allows + * them to work in linux-user mode which doesn't provide functional + * get_cp15/set_cp15 helpers, and is more efficient anyway. */ - if ((insn & 0x0fff0fff) == 0x0e070f90) { + switch ((insn & 0x0fff0fff)) { + case 0x0e070f90: /* 0,c7,c0,4: Standard v6 WFI (also used in some pre-v6 cores). * In v7, this must NOP. */ + if (IS_USER(s)) { + return 1; + } if (!arm_feature(env, ARM_FEATURE_V7)) { /* Wait for interrupt. */ gen_set_pc_im(s->pc); s->is_jmp = DISAS_WFI; } return 0; - } - - if ((insn & 0x0fff0fff) == 0x0e070f58) { + case 0x0e070f58: /* 0,c7,c8,2: Not all pre-v6 cores implemented this WFI, * so this is slightly over-broad. */ - if (!arm_feature(env, ARM_FEATURE_V6)) { + if (!IS_USER(s) && !arm_feature(env, ARM_FEATURE_V6)) { /* Wait for interrupt. */ gen_set_pc_im(s->pc); s->is_jmp = DISAS_WFI; return 0; } - /* Otherwise fall through to handle via helper function. + /* Otherwise continue to handle via helper function. * In particular, on v7 and some v6 cores this is one of * the VA-PA registers. */ + break; + case 0x0e070f3d: + /* 0,c7,c13,1: prefetch-by-MVA in v6, NOP in v7 */ + if (arm_feature(env, ARM_FEATURE_V6)) { + return IS_USER(s) ? 1 : 0; + } + break; + case 0x0e070f95: /* 0,c7,c5,4 : ISB */ + case 0x0e070f9a: /* 0,c7,c10,4: DSB */ + case 0x0e070fba: /* 0,c7,c10,5: DMB */ + /* Barriers in both v6 and v7 */ + if (arm_feature(env, ARM_FEATURE_V6)) { + return 0; + } + break; + default: + break; + } + + if (IS_USER(s) && !cp15_user_ok(env, insn)) { + return 1; } rd = (insn >> 12) & 0xf; From 934814f1984346af3e95306648cf20195269b098 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Jul 2011 00:51:19 +0000 Subject: [PATCH 5/7] target-arm: Handle UNDEF and UNPREDICTABLE cases for VLDM, VSTM Handle the UNDEF and UNPREDICTABLE cases for VLDM and VSTM. In particular, we now generate an undef exception for overlarge imm8 values rather than generating 1000+ TCG ops and hitting an assertion. Signed-off-by: Peter Maydell --- target-arm/translate.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index c7961b8097..7acb498277 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3397,17 +3397,18 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) VFP_DREG_D(rd, insn); else rd = VFP_SREG_D(insn); - if (s->thumb && rn == 15) { - addr = tcg_temp_new_i32(); - tcg_gen_movi_i32(addr, s->pc & ~2); - } else { - addr = load_reg(s, rn); - } if ((insn & 0x01200000) == 0x01000000) { /* Single load/store */ offset = (insn & 0xff) << 2; if ((insn & (1 << 23)) == 0) offset = -offset; + if (s->thumb && rn == 15) { + /* This is actually UNPREDICTABLE */ + addr = tcg_temp_new_i32(); + tcg_gen_movi_i32(addr, s->pc & ~2); + } else { + addr = load_reg(s, rn); + } tcg_gen_addi_i32(addr, addr, offset); if (insn & (1 << 20)) { gen_vfp_ld(s, dp, addr); @@ -3419,11 +3420,34 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) tcg_temp_free_i32(addr); } else { /* load/store multiple */ + int w = insn & (1 << 21); if (dp) n = (insn >> 1) & 0x7f; else n = insn & 0xff; + if (w && !(((insn >> 23) ^ (insn >> 24)) & 1)) { + /* P == U , W == 1 => UNDEF */ + return 1; + } + if (n == 0 || (rd + n) > 32 || (dp && n > 16)) { + /* UNPREDICTABLE cases for bad immediates: we choose to + * UNDEF to avoid generating huge numbers of TCG ops + */ + return 1; + } + if (rn == 15 && w) { + /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */ + return 1; + } + + if (s->thumb && rn == 15) { + /* This is actually UNPREDICTABLE */ + addr = tcg_temp_new_i32(); + tcg_gen_movi_i32(addr, s->pc & ~2); + } else { + addr = load_reg(s, rn); + } if (insn & (1 << 24)) /* pre-decrement */ tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2)); @@ -3443,7 +3467,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) } tcg_gen_addi_i32(addr, addr, offset); } - if (insn & (1 << 21)) { + if (w) { /* writeback */ if (insn & (1 << 24)) offset = -offset * n; From 6e0c0ed185227c301f643281220603fcaf217b31 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Jul 2011 00:51:20 +0000 Subject: [PATCH 6/7] target-arm: UNDEF on a VCVTT/VCVTB UNPREDICTABLE to avoid TCG assert VCVTT/VCVTB with bit 8 set is UNPREDICTABLE; we choose to UNDEF. This avoids a TCG assert later when the VCVTT/VCVTB code tries to use a source register that wasn't ever set up. We pull the check for the presence of the half-precision extension up in to this common code as well. Signed-off-by: Peter Maydell --- target-arm/translate.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 7acb498277..fcb41d1cbe 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3071,6 +3071,17 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) /* Source and destination the same. */ gen_mov_F0_vreg(dp, rd); break; + case 4: + case 5: + case 6: + case 7: + /* VCVTB, VCVTT: only present with the halfprec extension, + * UNPREDICTABLE if bit 8 is set (we choose to UNDEF) + */ + if (dp || !arm_feature(env, ARM_FEATURE_VFP_FP16)) { + return 1; + } + /* Otherwise fall through */ default: /* One source operand. */ gen_mov_F0_vreg(dp, rm); @@ -3167,24 +3178,18 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_vfp_sqrt(dp); break; case 4: /* vcvtb.f32.f16 */ - if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) - return 1; tmp = gen_vfp_mrs(); tcg_gen_ext16u_i32(tmp, tmp); gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env); tcg_temp_free_i32(tmp); break; case 5: /* vcvtt.f32.f16 */ - if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) - return 1; tmp = gen_vfp_mrs(); tcg_gen_shri_i32(tmp, tmp, 16); gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env); tcg_temp_free_i32(tmp); break; case 6: /* vcvtb.f16.f32 */ - if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) - return 1; tmp = tcg_temp_new_i32(); gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); gen_mov_F0_vreg(0, rd); @@ -3195,8 +3200,6 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_vfp_msr(tmp); break; case 7: /* vcvtt.f16.f32 */ - if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) - return 1; tmp = tcg_temp_new_i32(); gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); tcg_gen_shli_i32(tmp, tmp, 16); From a492892cbee7ee3244fa63c993b55428b87fc093 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Jul 2011 00:51:21 +0000 Subject: [PATCH 7/7] target-arm: Don't print debug messages for various UNDEF cases Remove some stray printfs for cases which don't generally happen (some VFP UNDEF cases, reads and writes to unknown cp14 registers); we should simply generate an UNDEF when the instruction is executed. Signed-off-by: Peter Maydell --- target-arm/translate.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index fcb41d1cbe..75c0ad413a 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3288,12 +3288,10 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_vfp_toul(dp, 32 - rm, 0); break; default: /* undefined */ - printf ("rn:%d\n", rn); return 1; } break; default: /* undefined */ - printf ("op:%d\n", op); return 1; } @@ -6372,8 +6370,6 @@ static int disas_cp14_read(CPUState * env, DisasContext *s, uint32_t insn) return 0; } } - fprintf(stderr, "Unknown cp14 read op1:%d crn:%d crm:%d op2:%d\n", - op1, crn, crm, op2); return 1; } @@ -6405,8 +6401,6 @@ static int disas_cp14_write(CPUState * env, DisasContext *s, uint32_t insn) return 0; } } - fprintf(stderr, "Unknown cp14 write op1:%d crn:%d crm:%d op2:%d\n", - op1, crn, crm, op2); return 1; }