Commit 64ea3d67 authored by Stefan Markovic's avatar Stefan Markovic Committed by Aleksandar Markovic
Browse files

linux-user: Add prctl() PR_SET_FP_MODE and PR_GET_FP_MODE implementations



Implement MIPS specific prctl() PR_SET_FP_MODE and PR_GET_FP_MODE emulation.

Reviewed-by: default avatarAleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: default avatarStefan Markovic <smarkovic@wavecomp.com>
parent 0c1bbedc
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -247,5 +247,7 @@ static inline abi_ulong target_shmlba(CPUMIPSState *env)
/* MIPS-specific prctl() options */
#define TARGET_PR_SET_FP_MODE  45
#define TARGET_PR_GET_FP_MODE  46
#define TARGET_PR_FP_MODE_FR   (1 << 0)
#define TARGET_PR_FP_MODE_FRE  (1 << 1)

#endif /* MIPS_TARGET_SYSCALL_H */
+2 −0
Original line number Diff line number Diff line
@@ -244,5 +244,7 @@ static inline abi_ulong target_shmlba(CPUMIPSState *env)
/* MIPS-specific prctl() options */
#define TARGET_PR_SET_FP_MODE  45
#define TARGET_PR_GET_FP_MODE  46
#define TARGET_PR_FP_MODE_FR   (1 << 0)
#define TARGET_PR_FP_MODE_FRE  (1 << 1)

#endif /* MIPS64_TARGET_SYSCALL_H */
+58 −4
Original line number Diff line number Diff line
@@ -9529,11 +9529,65 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
#endif
#ifdef TARGET_MIPS
        case TARGET_PR_GET_FP_MODE:
            /* TODO: Implement TARGET_PR_SET_FP_MODE handling.*/
            return -TARGET_EINVAL;
        {
            CPUMIPSState *env = ((CPUMIPSState *)cpu_env);
            ret = 0;
            if (env->CP0_Status & (1 << CP0St_FR)) {
                ret |= TARGET_PR_FP_MODE_FR;
            }
            if (env->CP0_Config5 & (1 << CP0C5_FRE)) {
                ret |= TARGET_PR_FP_MODE_FRE;
            }
            return ret;
        }
        case TARGET_PR_SET_FP_MODE:
            /* TODO: Implement TARGET_PR_GET_FP_MODE handling.*/
            return -TARGET_EINVAL;
        {
            CPUMIPSState *env = ((CPUMIPSState *)cpu_env);
            bool old_fr = env->CP0_Status & (1 << CP0St_FR);
            bool new_fr = arg2 & TARGET_PR_FP_MODE_FR;
            bool new_fre = arg2 & TARGET_PR_FP_MODE_FRE;

            if (new_fr && !(env->active_fpu.fcr0 & (1 << FCR0_F64))) {
                /* FR1 is not supported */
                return -TARGET_EOPNOTSUPP;
            }
            if (!new_fr && (env->active_fpu.fcr0 & (1 << FCR0_F64))
                && !(env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) {
                /* cannot set FR=0 */
                return -TARGET_EOPNOTSUPP;
            }
            if (new_fre && !(env->active_fpu.fcr0 & (1 << FCR0_FREP))) {
                /* Cannot set FRE=1 */
                return -TARGET_EOPNOTSUPP;
            }

            int i;
            fpr_t *fpr = env->active_fpu.fpr;
            for (i = 0; i < 32 ; i += 2) {
                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);
                env->hflags |= MIPS_HFLAG_F64;
            } else {
                env->CP0_Status &= ~(1 << CP0St_FR);
            }
            if (new_fre) {
                env->CP0_Config5 |= (1 << CP0C5_FRE);
                if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
                    env->hflags |= MIPS_HFLAG_FRE;
                }
            } else {
                env->CP0_Config5 &= ~(1 << CP0C5_FRE);
            }

            return 0;
        }
#endif /* MIPS */
#ifdef TARGET_AARCH64
        case TARGET_PR_SVE_SET_VL: