summaryrefslogtreecommitdiff
path: root/target-arm
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2011-05-03 20:16:18 -0300
committerMarcelo Tosatti <mtosatti@redhat.com>2011-05-03 20:16:18 -0300
commit28262112181f27f302b5186f0df6428df6b513e7 (patch)
treec1a12fd82d869eb8c57da3e3314abb3437f3a8a1 /target-arm
parent70757dcaa40e14978bf287084d8fab9efb815a2d (diff)
parent4eb1a092e5810298b2baf4b12d9f52ea0d52322f (diff)
Merge branch 'upstream-merge'HEADmaster
* upstream-merge: (197 commits) NBD: Avoid leaking a couple of strings when the NBD device is closed qemu-progress.c: printf isn't signal safe ide/atapi: fix set but unused atapi: Explain why we need a 'media not present' state atapi: Move comment to proper place qemu-img resize: Fix option parsing lm32: add Milkymist Minimac2 support milkymist-sysctl: fix timers milkymist-vgafb: fix console resizing lm32: fix exception handling kvm: use qemu_free consistently kvm: Install specialized interrupt handler fix crash in migration, 32-bit userspace on 64-bit host Redirect cpu_interrupt to callback handler Break up user and system cpu_interrupt implementations kvm: create kvmclock when one of the flags are present kvm: add kvmclock to its second bit x86: Allow multiple cpu feature matches of lookup_feature kvm: use kernel-provided para_features instead of statically coming up with new capabilities Don't zero out buffer in sched_getaffinity ... Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'target-arm')
-rw-r--r--target-arm/cpu.h3
-rw-r--r--target-arm/helper.c22
-rw-r--r--target-arm/helper.h (renamed from target-arm/helpers.h)0
-rw-r--r--target-arm/iwmmxt_helper.c2
-rw-r--r--target-arm/neon_helper.c2
-rw-r--r--target-arm/op_helper.c4
-rw-r--r--target-arm/translate.c89
7 files changed, 105 insertions, 17 deletions
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index e247a7ade..d5af64465 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -363,6 +363,7 @@ enum arm_features {
ARM_FEATURE_V7MP, /* v7 Multiprocessing Extensions */
ARM_FEATURE_V4T,
ARM_FEATURE_V5,
+ ARM_FEATURE_STRONGARM,
};
static inline int arm_feature(CPUARMState *env, int feature)
@@ -393,6 +394,8 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
#define ARM_CPUID_ARM946 0x41059461
#define ARM_CPUID_TI915T 0x54029152
#define ARM_CPUID_TI925T 0x54029252
+#define ARM_CPUID_SA1100 0x4401A11B
+#define ARM_CPUID_SA1110 0x6901B119
#define ARM_CPUID_PXA250 0x69052100
#define ARM_CPUID_PXA255 0x69052d00
#define ARM_CPUID_PXA260 0x69052903
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 9172fc727..62ae72ec2 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -5,7 +5,7 @@
#include "cpu.h"
#include "exec-all.h"
#include "gdbstub.h"
-#include "helpers.h"
+#include "helper.h"
#include "qemu-common.h"
#include "host-utils.h"
#if !defined(CONFIG_USER_ONLY)
@@ -214,6 +214,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c0_cachetype = 0xd172172;
env->cp15.c1_sys = 0x00000078;
break;
+ case ARM_CPUID_SA1100:
+ case ARM_CPUID_SA1110:
+ set_feature(env, ARM_FEATURE_STRONGARM);
+ env->cp15.c1_sys = 0x00000070;
+ break;
default:
cpu_abort(env, "Bad CPU ID: %x\n", id);
break;
@@ -378,6 +383,8 @@ static const struct arm_cpu_t arm_cpu_names[] = {
{ ARM_CPUID_CORTEXA9, "cortex-a9"},
{ ARM_CPUID_TI925T, "ti925t" },
{ ARM_CPUID_PXA250, "pxa250" },
+ { ARM_CPUID_SA1100, "sa1100" },
+ { ARM_CPUID_SA1110, "sa1110" },
{ ARM_CPUID_PXA255, "pxa255" },
{ ARM_CPUID_PXA260, "pxa260" },
{ ARM_CPUID_PXA261, "pxa261" },
@@ -1378,7 +1385,7 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
/* This may enable/disable the MMU, so do a TLB flush. */
tlb_flush(env, 1);
break;
- case 1: /* Auxiliary cotrol register. */
+ case 1: /* Auxiliary control register. */
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
env->cp15.c1_xscaleauxcr = val;
break;
@@ -1553,6 +1560,8 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
case 9:
if (arm_feature(env, ARM_FEATURE_OMAPCP))
break;
+ if (arm_feature(env, ARM_FEATURE_STRONGARM))
+ break; /* Ignore ReadBuffer access */
switch (crm) {
case 0: /* Cache lockdown. */
switch (op1) {
@@ -2542,6 +2551,7 @@ float64 VFP_HELPER(sito, d)(uint32_t x, CPUState *env)
uint32_t VFP_HELPER(toui, s)(float32 x, CPUState *env)
{
if (float32_is_any_nan(x)) {
+ float_raise(float_flag_invalid, &env->vfp.fp_status);
return 0;
}
return float32_to_uint32(x, &env->vfp.fp_status);
@@ -2550,6 +2560,7 @@ uint32_t VFP_HELPER(toui, s)(float32 x, CPUState *env)
uint32_t VFP_HELPER(toui, d)(float64 x, CPUState *env)
{
if (float64_is_any_nan(x)) {
+ float_raise(float_flag_invalid, &env->vfp.fp_status);
return 0;
}
return float64_to_uint32(x, &env->vfp.fp_status);
@@ -2558,6 +2569,7 @@ uint32_t VFP_HELPER(toui, d)(float64 x, CPUState *env)
uint32_t VFP_HELPER(tosi, s)(float32 x, CPUState *env)
{
if (float32_is_any_nan(x)) {
+ float_raise(float_flag_invalid, &env->vfp.fp_status);
return 0;
}
return float32_to_int32(x, &env->vfp.fp_status);
@@ -2566,6 +2578,7 @@ uint32_t VFP_HELPER(tosi, s)(float32 x, CPUState *env)
uint32_t VFP_HELPER(tosi, d)(float64 x, CPUState *env)
{
if (float64_is_any_nan(x)) {
+ float_raise(float_flag_invalid, &env->vfp.fp_status);
return 0;
}
return float64_to_int32(x, &env->vfp.fp_status);
@@ -2574,6 +2587,7 @@ uint32_t VFP_HELPER(tosi, d)(float64 x, CPUState *env)
uint32_t VFP_HELPER(touiz, s)(float32 x, CPUState *env)
{
if (float32_is_any_nan(x)) {
+ float_raise(float_flag_invalid, &env->vfp.fp_status);
return 0;
}
return float32_to_uint32_round_to_zero(x, &env->vfp.fp_status);
@@ -2582,6 +2596,7 @@ uint32_t VFP_HELPER(touiz, s)(float32 x, CPUState *env)
uint32_t VFP_HELPER(touiz, d)(float64 x, CPUState *env)
{
if (float64_is_any_nan(x)) {
+ float_raise(float_flag_invalid, &env->vfp.fp_status);
return 0;
}
return float64_to_uint32_round_to_zero(x, &env->vfp.fp_status);
@@ -2590,6 +2605,7 @@ uint32_t VFP_HELPER(touiz, d)(float64 x, CPUState *env)
uint32_t VFP_HELPER(tosiz, s)(float32 x, CPUState *env)
{
if (float32_is_any_nan(x)) {
+ float_raise(float_flag_invalid, &env->vfp.fp_status);
return 0;
}
return float32_to_int32_round_to_zero(x, &env->vfp.fp_status);
@@ -2598,6 +2614,7 @@ uint32_t VFP_HELPER(tosiz, s)(float32 x, CPUState *env)
uint32_t VFP_HELPER(tosiz, d)(float64 x, CPUState *env)
{
if (float64_is_any_nan(x)) {
+ float_raise(float_flag_invalid, &env->vfp.fp_status);
return 0;
}
return float64_to_int32_round_to_zero(x, &env->vfp.fp_status);
@@ -2636,6 +2653,7 @@ uint##fsz##_t VFP_HELPER(to##name, p)(float##fsz x, uint32_t shift, \
{ \
float##fsz tmp; \
if (float##fsz##_is_any_nan(x)) { \
+ float_raise(float_flag_invalid, &env->vfp.fp_status); \
return 0; \
} \
tmp = float##fsz##_scalbn(x, shift, &env->vfp.fp_status); \
diff --git a/target-arm/helpers.h b/target-arm/helper.h
index ae701e845..ae701e845 100644
--- a/target-arm/helpers.h
+++ b/target-arm/helper.h
diff --git a/target-arm/iwmmxt_helper.c b/target-arm/iwmmxt_helper.c
index 3941f1fd8..ebe6eb9fa 100644
--- a/target-arm/iwmmxt_helper.c
+++ b/target-arm/iwmmxt_helper.c
@@ -24,7 +24,7 @@
#include "cpu.h"
#include "exec.h"
-#include "helpers.h"
+#include "helper.h"
/* iwMMXt macros extracted from GNU gdb. */
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 7df925ad3..f5b173aa7 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -11,7 +11,7 @@
#include "cpu.h"
#include "exec.h"
-#include "helpers.h"
+#include "helper.h"
#define SIGNBIT (uint32_t)0x80000000
#define SIGNBIT64 ((uint64_t)1 << 63)
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 3de261034..8334fbcf6 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -17,7 +17,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "exec.h"
-#include "helpers.h"
+#include "helper.h"
#define SIGNBIT (uint32_t)0x80000000
#define SIGNBIT64 ((uint64_t)1 << 63)
@@ -90,7 +90,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc, NULL);
+ cpu_restore_state(tb, env, pc);
}
}
raise_exception(env->exception_index);
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 6190028d0..a1af436e3 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -30,9 +30,9 @@
#include "tcg-op.h"
#include "qemu-log.h"
-#include "helpers.h"
+#include "helper.h"
#define GEN_HELPER 1
-#include "helpers.h"
+#include "helper.h"
#define ENABLE_ARCH_4T arm_feature(env, ARM_FEATURE_V4T)
#define ENABLE_ARCH_5 arm_feature(env, ARM_FEATURE_V5)
@@ -129,7 +129,7 @@ void arm_translate_init(void)
#endif
#define GEN_HELPER 2
-#include "helpers.h"
+#include "helper.h"
}
static inline TCGv load_cpu_offset(int offset)
@@ -3830,6 +3830,21 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
size = (insn >> 6) & 3;
if (op > 10)
return 1;
+ /* Catch UNDEF cases for bad values of align field */
+ switch (op & 0xc) {
+ case 4:
+ if (((insn >> 5) & 1) == 1) {
+ return 1;
+ }
+ break;
+ case 8:
+ if (((insn >> 4) & 3) == 3) {
+ return 1;
+ }
+ break;
+ default:
+ break;
+ }
nregs = neon_ls_element_type[op].nregs;
interleave = neon_ls_element_type[op].interleave;
spacing = neon_ls_element_type[op].spacing;
@@ -3975,6 +3990,7 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
stride = (1 << size) * nregs;
} else {
/* Single element. */
+ int idx = (insn >> 4) & 0xf;
pass = (insn >> 7) & 1;
switch (size) {
case 0:
@@ -3993,6 +4009,39 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
abort();
}
nregs = ((insn >> 8) & 3) + 1;
+ /* Catch the UNDEF cases. This is unavoidably a bit messy. */
+ switch (nregs) {
+ case 1:
+ if (((idx & (1 << size)) != 0) ||
+ (size == 2 && ((idx & 3) == 1 || (idx & 3) == 2))) {
+ return 1;
+ }
+ break;
+ case 3:
+ if ((idx & 1) != 0) {
+ return 1;
+ }
+ /* fall through */
+ case 2:
+ if (size == 2 && (idx & 2) != 0) {
+ return 1;
+ }
+ break;
+ case 4:
+ if ((size == 2) && ((idx & 3) == 3)) {
+ return 1;
+ }
+ break;
+ default:
+ abort();
+ }
+ if ((rd + stride * (nregs - 1)) > 31) {
+ /* Attempts to write off the end of the register file
+ * are UNPREDICTABLE; we choose to UNDEF because otherwise
+ * the neon_load_reg() would write off the end of the array.
+ */
+ return 1;
+ }
addr = tcg_temp_new_i32();
load_reg_var(s, addr, rn);
for (reg = 0; reg < nregs; reg++) {
@@ -7967,7 +8016,8 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
}
}
} else {
- int i;
+ int i, loaded_base = 0;
+ TCGv loaded_var;
/* Load/store multiple. */
addr = load_reg(s, rn);
offset = 0;
@@ -7979,6 +8029,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
tcg_gen_addi_i32(addr, addr, -offset);
}
+ TCGV_UNUSED(loaded_var);
for (i = 0; i < 16; i++) {
if ((insn & (1 << i)) == 0)
continue;
@@ -7987,6 +8038,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
tmp = gen_ld32(addr, IS_USER(s));
if (i == 15) {
gen_bx(s, tmp);
+ } else if (i == rn) {
+ loaded_var = tmp;
+ loaded_base = 1;
} else {
store_reg(s, i, tmp);
}
@@ -7997,6 +8051,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
}
tcg_gen_addi_i32(addr, addr, 4);
}
+ if (loaded_base) {
+ store_reg(s, rn, loaded_var);
+ }
if (insn & (1 << 21)) {
/* Base register writeback. */
if (insn & (1 << 24)) {
@@ -9397,7 +9454,10 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
break;
case 12:
+ {
/* load/store multiple */
+ TCGv loaded_var;
+ TCGV_UNUSED(loaded_var);
rn = (insn >> 8) & 0x7;
addr = load_reg(s, rn);
for (i = 0; i < 8; i++) {
@@ -9405,7 +9465,11 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
if (insn & (1 << 11)) {
/* load */
tmp = gen_ld32(addr, IS_USER(s));
- store_reg(s, i, tmp);
+ if (i == rn) {
+ loaded_var = tmp;
+ } else {
+ store_reg(s, i, tmp);
+ }
} else {
/* store */
tmp = load_reg(s, i);
@@ -9415,14 +9479,18 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
tcg_gen_addi_i32(addr, addr, 4);
}
}
- /* Base register writeback. */
if ((insn & (1 << rn)) == 0) {
+ /* base reg not in list: base register writeback */
store_reg(s, rn, addr);
} else {
+ /* base reg in list: if load, complete it now */
+ if (insn & (1 << 11)) {
+ store_reg(s, rn, loaded_var);
+ }
tcg_temp_free_i32(addr);
}
break;
-
+ }
case 13:
/* conditional branch or swi */
cond = (insn >> 8) & 0xf;
@@ -9551,8 +9619,8 @@ static inline void gen_intermediate_code_internal(CPUState *env,
* This is handled in the same way as restoration of the
* PC in these situations: we will be called again with search_pc=1
* and generate a mapping of the condexec bits for each PC in
- * gen_opc_condexec_bits[]. gen_pc_load[] then uses this to restore
- * the condexec bits.
+ * gen_opc_condexec_bits[]. restore_state_to_opc() then uses
+ * this to restore the condexec bits.
*
* Note that there are no instructions which can read the condexec
* bits, and none which can write non-static values to them, so
@@ -9817,8 +9885,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
#endif
}
-void gen_pc_load(CPUState *env, TranslationBlock *tb,
- unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
{
env->regs[15] = gen_opc_pc[pc_pos];
env->condexec_bits = gen_opc_condexec_bits[pc_pos];