[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH] linux-user: Fix support MIPS o32 FP64 mode
From: |
YunQiang Su |
Subject: |
[Qemu-devel] [PATCH] linux-user: Fix support MIPS o32 FP64 mode |
Date: |
Tue, 19 Dec 2017 19:24:38 +0800 |
MIPS o32 has a mode called FP64, who has 32 64Bit FPU registers.
To use it:
add PR_GET_FP_MODE and PR_SET_FP_MODE options for prctl
set CP0St_FR when binary as EF_MIPS_FP64
https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking
Signed-off-by: YunQiang Su <address@hidden>
---
linux-user/main.c | 3 +++
linux-user/syscall.c | 24 +++++++++++++++++++++
target/mips/cpu.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++
target/mips/cpu.h | 9 ++++++++
4 files changed, 95 insertions(+)
diff --git a/linux-user/main.c b/linux-user/main.c
index 2fd2a143ed..f2b02a99a2 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -4750,6 +4750,9 @@ int main(int argc, char **argv, char **envp)
}
restore_snan_bit_mode(env);
}
+ if ((info->elf_flags & EF_MIPS_FP64) != 0) {
+ env->CP0_Status |= (1 << CP0St_FR);
+ }
}
#elif defined(TARGET_NIOS2)
{
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 11c9116c4a..664dacda33 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -10530,6 +10530,30 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
arg1,
* need. */
ret = -TARGET_EINVAL;
break;
+#ifdef TARGET_MIPS
+ case PR_GET_FP_MODE:
+ {
+ CPUMIPSState *env = ((CPUMIPSState *)cpu_env);
+ ret = 0;
+ if (env->CP0_Status & (1 << CP0St_FR)) {
+ ret |= PR_FP_MODE_FR;
+ }
+ if (env->CP0_Config5 & (1 << CP0C5_FRE)) {
+ ret |= PR_FP_MODE_FRE;
+ }
+ break;
+ }
+ case PR_SET_FP_MODE:
+ {
+ CPUMIPSState *env = ((CPUMIPSState *)cpu_env);
+ ret = mips_prctl_set_fp_mode(env, arg2);
+ if (ret < 0) {
+ ret = -TARGET_EOPNOTSUPP;
+ goto fail;
+ }
+ break;
+ }
+#endif
default:
/* Most prctl options have no pointer arguments */
ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
diff --git a/target/mips/cpu.c b/target/mips/cpu.c
index 069f93560e..6cf1907f9c 100644
--- a/target/mips/cpu.c
+++ b/target/mips/cpu.c
@@ -246,4 +246,63 @@ static void mips_cpu_register_types(void)
}
}
+#ifdef CONFIG_USER_ONLY
+abi_long mips_prctl_set_fp_mode(CPUMIPSState *env, abi_long arg2)
+{
+ abi_long ret;
+ CPUState *other_cpu;
+ bool old_fr = env->CP0_Status & (1 << CP0St_FR);
+ bool new_fr = arg2 & PR_FP_MODE_FR;
+ bool new_fre = arg2 & PR_FP_MODE_FRE;
+
+ if (new_fr && !(env->active_fpu.fcr0 & (1 << FCR0_F64))) {
+ /* FR1 is not supported */
+ ret = -1;
+ return ret;
+ }
+
+ if (!new_fr && (env->active_fpu.fcr0 & (1 << FCR0_F64))
+ && !(env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) {
+ /* cannot set FR=0 */
+ ret = -1;
+ return ret;
+ }
+
+ if (new_fre && !(env->active_fpu.fcr0 & (1 << FCR0_FREP))) {
+ /* Cannot set FRE=1 */
+ ret = -1;
+ return ret;
+ }
+
+ start_exclusive();
+ CPU_FOREACH(other_cpu) {
+ int i;
+ MIPSCPU *cpu = MIPS_CPU(other_cpu);
+ env = &cpu->env;
+ for (i = 0; i < 32 ; i += 2) {
+ fpr_t *fpr = env->active_fpu.fpr;
+ if (!old_fr && new_fr) {
+ fpr[i].w[!FP_ENDIAN_IDX] = fpr[i + 1].w[FP_ENDIAN_IDX];
+ } else if (old_fr && !new_fr) {
+ fpr[i + 1].w[FP_ENDIAN_IDX] = fpr[i].w[!FP_ENDIAN_IDX];
+ }
+ }
+ if (new_fr) {
+ env->CP0_Status |= (1 << CP0St_FR);
+ } else {
+ env->CP0_Status &= ~(1 << CP0St_FR);
+ }
+ if (new_fre) {
+ env->CP0_Config5 |= (1 << CP0C5_FRE);
+ } else {
+ env->CP0_Config5 &= ~(1 << CP0C5_FRE);
+ }
+ compute_hflags(env);
+ }
+ end_exclusive();
+ ret = 0;
+ return ret;
+}
+#endif
+
type_init(mips_cpu_register_types)
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index 7f8ba5ff3e..b5d9aac6d0 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -769,4 +769,13 @@ static inline void cpu_get_tb_cpu_state(CPUMIPSState *env,
target_ulong *pc,
MIPS_HFLAG_HWRENA_ULR);
}
+/* prctl interface. */
+#if defined(CONFIG_USER_ONLY)
+#define PR_SET_FP_MODE 45
+#define PR_GET_FP_MODE 46
+#define PR_FP_MODE_FR (1 << 0)
+#define PR_FP_MODE_FRE (1 << 1)
+abi_long mips_prctl_set_fp_mode(CPUMIPSState *env, abi_long arg2);
+#endif
+
#endif /* MIPS_CPU_H */
--
2.15.1
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] [PATCH] linux-user: Fix support MIPS o32 FP64 mode,
YunQiang Su <=