diff options
author | Anthony Liguori <aliguori@amazon.com> | 2014-01-09 11:23:49 -0800 |
---|---|---|
committer | Anthony Liguori <aliguori@amazon.com> | 2014-01-09 11:23:49 -0800 |
commit | b61740dbef8d1c8fda8a0f46ecb617e6e865e9e2 (patch) | |
tree | dc7b24cfa11d1c99a8099fd3fb1e401515afa59e /linux-user | |
parent | f976b09ea249cccc3fd41c98aaf6512908db0bae (diff) | |
parent | 8900aad218f8f2348bcd688eacf06d6c1f66bc69 (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.h | 1 | ||||
-rw-r--r-- | linux-user/aarch64/target_cpu.h | 5 | ||||
-rw-r--r-- | linux-user/arm/target_cpu.h | 2 | ||||
-rw-r--r-- | linux-user/main.c | 154 | ||||
-rw-r--r-- | linux-user/signal.c | 10 |
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; } |