aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@amazon.com>2014-01-09 11:23:49 -0800
committerAnthony Liguori <aliguori@amazon.com>2014-01-09 11:23:49 -0800
commitb61740dbef8d1c8fda8a0f46ecb617e6e865e9e2 (patch)
treedc7b24cfa11d1c99a8099fd3fb1e401515afa59e /linux-user
parentf976b09ea249cccc3fd41c98aaf6512908db0bae (diff)
parent8900aad218f8f2348bcd688eacf06d6c1f66bc69 (diff)
Merge remote-tracking branch 'pmaydell/tags/pull-target-arm-20140108' into staging
target-arm queue: * further A64 decoder patches, including enabling the aarch64-linux-user target; this includes full floating point support. Neon is not yet supported. * cadence UART model fixes. * some minor bug fixes and cleanups. * all the softfloat fixes required by the new A64 instructions; several of these will also be used by PPC. # gpg: Signature made Wed 08 Jan 2014 11:25:12 AM PST using RSA key ID 14360CDE # gpg: Can't check signature: public key not found * pmaydell/tags/pull-target-arm-20140108: (76 commits) target-arm: A64: Add support for FCVT between half, single and double target-arm: A64: Add 1-source 32-to-32 and 64-to-64 FP instructions target-arm: A64: Add floating-point<->integer conversion instructions target-arm: A64: Add floating-point<->fixed-point instructions target-arm: A64: Add extra VFP fixed point conversion helpers target-arm: Ignore most exceptions from scalbn when doing fixpoint conversion target-arm: Rename A32 VFP conversion helpers target-arm: Prepare VFP_CONV_FIX helpers for A64 uses softfloat: Add support for ties-away rounding softfloat: Refactor code handling various rounding modes softfloat: Add float16 <=> float64 conversion functions softfloat: Factor out RoundAndPackFloat16 and NormalizeFloat16Subnormal softfloat: Provide complete set of accessors for fp state softfloat: Fix float64_to_uint32_round_to_zero softfloat: Fix float64_to_uint32 softfloat: Fix float64_to_uint64_round_to_zero softfloat: Add float32_to_uint64() softfloat: Fix factor 2 error for scalbn on denormal inputs softfloat: Only raise Invalid when conversions to int are out of range softfloat: Fix float64_to_uint64 ... Message-id: 1389209439-25448-1-git-send-email-peter.maydell@linaro.org Signed-off-by: Anthony Liguori <aliguori@amazon.com>
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/aarch64/syscall.h1
-rw-r--r--linux-user/aarch64/target_cpu.h5
-rw-r--r--linux-user/arm/target_cpu.h2
-rw-r--r--linux-user/main.c154
-rw-r--r--linux-user/signal.c10
5 files changed, 153 insertions, 19 deletions
diff --git a/linux-user/aarch64/syscall.h b/linux-user/aarch64/syscall.h
index aef419efeb..18f44a8a40 100644
--- a/linux-user/aarch64/syscall.h
+++ b/linux-user/aarch64/syscall.h
@@ -7,3 +7,4 @@ struct target_pt_regs {
#define UNAME_MACHINE "aarch64"
#define UNAME_MINIMUM_RELEASE "3.8.0"
+#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/aarch64/target_cpu.h b/linux-user/aarch64/target_cpu.h
index 6f5539b50f..21560ef832 100644
--- a/linux-user/aarch64/target_cpu.h
+++ b/linux-user/aarch64/target_cpu.h
@@ -29,7 +29,10 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls)
{
- env->sr.tpidr_el0 = newtls;
+ /* Note that AArch64 Linux keeps the TLS pointer in TPIDR; this is
+ * different from AArch32 Linux, which uses TPIDRRO.
+ */
+ env->cp15.tpidr_el0 = newtls;
}
#endif
diff --git a/linux-user/arm/target_cpu.h b/linux-user/arm/target_cpu.h
index ed323c079d..39d65b692b 100644
--- a/linux-user/arm/target_cpu.h
+++ b/linux-user/arm/target_cpu.h
@@ -29,7 +29,7 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls)
{
- env->cp15.c13_tls2 = newtls;
+ env->cp15.tpidrro_el0 = newtls;
}
#endif
diff --git a/linux-user/main.c b/linux-user/main.c
index 54f71fe8f6..cabc9e1a0e 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -566,7 +566,7 @@ do_kernel_trap(CPUARMState *env)
end_exclusive();
break;
case 0xffff0fe0: /* __kernel_get_tls */
- env->regs[0] = env->cp15.c13_tls2;
+ env->regs[0] = env->cp15.tpidrro_el0;
break;
case 0xffff0f60: /* __kernel_cmpxchg64 */
arm_kernel_cmpxchg64_helper(env);
@@ -585,20 +585,25 @@ do_kernel_trap(CPUARMState *env)
return 0;
}
-#endif
+/* Store exclusive handling for AArch32 */
static int do_strex(CPUARMState *env)
{
- uint32_t val;
+ uint64_t val;
int size;
int rc = 1;
int segv = 0;
uint32_t addr;
start_exclusive();
- addr = env->exclusive_addr;
- if (addr != env->exclusive_test) {
+ if (env->exclusive_addr != env->exclusive_test) {
goto fail;
}
+ /* We know we're always AArch32 so the address is in uint32_t range
+ * unless it was the -1 exclusive-monitor-lost value (which won't
+ * match exclusive_test above).
+ */
+ assert(extract64(env->exclusive_addr, 32, 32) == 0);
+ addr = env->exclusive_addr;
size = env->exclusive_info & 0xf;
switch (size) {
case 0:
@@ -618,19 +623,19 @@ static int do_strex(CPUARMState *env)
env->cp15.c6_data = addr;
goto done;
}
- if (val != env->exclusive_val) {
- goto fail;
- }
if (size == 3) {
- segv = get_user_u32(val, addr + 4);
+ uint32_t valhi;
+ segv = get_user_u32(valhi, addr + 4);
if (segv) {
env->cp15.c6_data = addr + 4;
goto done;
}
- if (val != env->exclusive_high) {
- goto fail;
- }
+ val = deposit64(val, 32, 32, valhi);
}
+ if (val != env->exclusive_val) {
+ goto fail;
+ }
+
val = env->regs[(env->exclusive_info >> 8) & 0xf];
switch (size) {
case 0:
@@ -665,7 +670,6 @@ done:
return segv;
}
-#ifdef TARGET_ABI32
void cpu_loop(CPUARMState *env)
{
CPUState *cs = CPU(arm_env_get_cpu(env));
@@ -880,6 +884,122 @@ void cpu_loop(CPUARMState *env)
#else
+/*
+ * Handle AArch64 store-release exclusive
+ *
+ * rs = gets the status result of store exclusive
+ * rt = is the register that is stored
+ * rt2 = is the second register store (in STP)
+ *
+ */
+static int do_strex_a64(CPUARMState *env)
+{
+ uint64_t val;
+ int size;
+ bool is_pair;
+ int rc = 1;
+ int segv = 0;
+ uint64_t addr;
+ int rs, rt, rt2;
+
+ start_exclusive();
+ /* size | is_pair << 2 | (rs << 4) | (rt << 9) | (rt2 << 14)); */
+ size = extract32(env->exclusive_info, 0, 2);
+ is_pair = extract32(env->exclusive_info, 2, 1);
+ rs = extract32(env->exclusive_info, 4, 5);
+ rt = extract32(env->exclusive_info, 9, 5);
+ rt2 = extract32(env->exclusive_info, 14, 5);
+
+ addr = env->exclusive_addr;
+
+ if (addr != env->exclusive_test) {
+ goto finish;
+ }
+
+ switch (size) {
+ case 0:
+ segv = get_user_u8(val, addr);
+ break;
+ case 1:
+ segv = get_user_u16(val, addr);
+ break;
+ case 2:
+ segv = get_user_u32(val, addr);
+ break;
+ case 3:
+ segv = get_user_u64(val, addr);
+ break;
+ default:
+ abort();
+ }
+ if (segv) {
+ env->cp15.c6_data = addr;
+ goto error;
+ }
+ if (val != env->exclusive_val) {
+ goto finish;
+ }
+ if (is_pair) {
+ if (size == 2) {
+ segv = get_user_u32(val, addr + 4);
+ } else {
+ segv = get_user_u64(val, addr + 8);
+ }
+ if (segv) {
+ env->cp15.c6_data = addr + (size == 2 ? 4 : 8);
+ goto error;
+ }
+ if (val != env->exclusive_high) {
+ goto finish;
+ }
+ }
+ val = env->xregs[rt];
+ switch (size) {
+ case 0:
+ segv = put_user_u8(val, addr);
+ break;
+ case 1:
+ segv = put_user_u16(val, addr);
+ break;
+ case 2:
+ segv = put_user_u32(val, addr);
+ break;
+ case 3:
+ segv = put_user_u64(val, addr);
+ break;
+ }
+ if (segv) {
+ goto error;
+ }
+ if (is_pair) {
+ val = env->xregs[rt2];
+ if (size == 2) {
+ segv = put_user_u32(val, addr + 4);
+ } else {
+ segv = put_user_u64(val, addr + 8);
+ }
+ if (segv) {
+ env->cp15.c6_data = addr + (size == 2 ? 4 : 8);
+ goto error;
+ }
+ }
+ rc = 0;
+finish:
+ env->pc += 4;
+ /* rs == 31 encodes a write to the ZR, thus throwing away
+ * the status return. This is rather silly but valid.
+ */
+ if (rs < 31) {
+ env->xregs[rs] = rc;
+ }
+error:
+ /* instruction faulted, PC does not advance */
+ /* either way a strex releases any exclusive lock we have */
+ env->exclusive_addr = -1;
+ end_exclusive();
+ return segv;
+}
+
/* AArch64 main loop */
void cpu_loop(CPUARMState *env)
{
@@ -939,7 +1059,7 @@ void cpu_loop(CPUARMState *env)
}
break;
case EXCP_STREX:
- if (do_strex(env)) {
+ if (do_strex_a64(env)) {
addr = env->cp15.c6_data;
goto do_segv;
}
@@ -951,6 +1071,12 @@ void cpu_loop(CPUARMState *env)
abort();
}
process_pending_signals(env);
+ /* Exception return on AArch64 always clears the exclusive monitor,
+ * so any return to running guest code implies this.
+ * A strex (successful or otherwise) also clears the monitor, so
+ * we don't need to specialcase EXCP_STREX.
+ */
+ env->exclusive_addr = -1;
}
}
#endif /* ndef TARGET_ABI32 */
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 4e7148a2d6..6c74b18196 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1189,8 +1189,8 @@ static int target_setup_sigframe(struct target_rt_sigframe *sf,
__put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
#endif
}
- __put_user(/*env->fpsr*/0, &aux->fpsimd.fpsr);
- __put_user(/*env->fpcr*/0, &aux->fpsimd.fpcr);
+ __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
+ __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
__put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
__put_user(sizeof(struct target_fpsimd_context),
&aux->fpsimd.head.size);
@@ -1209,7 +1209,7 @@ static int target_restore_sigframe(CPUARMState *env,
int i;
struct target_aux_context *aux =
(struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
- uint32_t magic, size;
+ uint32_t magic, size, fpsr, fpcr;
uint64_t pstate;
target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
@@ -1235,6 +1235,10 @@ static int target_restore_sigframe(CPUARMState *env,
for (i = 0; i < 32 * 2; i++) {
__get_user(env->vfp.regs[i], &aux->fpsimd.vregs[i]);
}
+ __get_user(fpsr, &aux->fpsimd.fpsr);
+ vfp_set_fpsr(env, fpsr);
+ __get_user(fpcr, &aux->fpsimd.fpcr);
+ vfp_set_fpcr(env, fpcr);
return 0;
}