1 /* 2 * MIPS specific prctl functions for linux-user 3 * 4 * SPDX-License-Identifier: GPL-2.0-or-later 5 */ 6 #ifndef MIPS_TARGET_PRCTL_H 7 #define MIPS_TARGET_PRCTL_H 8 9 static abi_long do_prctl_get_fp_mode(CPUArchState *env) 10 { 11 abi_long ret = 0; 12 13 if (env->CP0_Status & (1 << CP0St_FR)) { 14 ret |= PR_FP_MODE_FR; 15 } 16 if (env->CP0_Config5 & (1 << CP0C5_FRE)) { 17 ret |= PR_FP_MODE_FRE; 18 } 19 return ret; 20 } 21 #define do_prctl_get_fp_mode do_prctl_get_fp_mode 22 23 static abi_long do_prctl_set_fp_mode(CPUArchState *env, abi_long arg2) 24 { 25 bool old_fr = env->CP0_Status & (1 << CP0St_FR); 26 bool old_fre = env->CP0_Config5 & (1 << CP0C5_FRE); 27 bool new_fr = arg2 & PR_FP_MODE_FR; 28 bool new_fre = arg2 & PR_FP_MODE_FRE; 29 const unsigned int known_bits = PR_FP_MODE_FR | PR_FP_MODE_FRE; 30 31 /* If nothing to change, return right away, successfully. */ 32 if (old_fr == new_fr && old_fre == new_fre) { 33 return 0; 34 } 35 /* Check the value is valid */ 36 if (arg2 & ~known_bits) { 37 return -TARGET_EOPNOTSUPP; 38 } 39 /* Setting FRE without FR is not supported. */ 40 if (new_fre && !new_fr) { 41 return -TARGET_EOPNOTSUPP; 42 } 43 if (new_fr && !(env->active_fpu.fcr0 & (1 << FCR0_F64))) { 44 /* FR1 is not supported */ 45 return -TARGET_EOPNOTSUPP; 46 } 47 if (!new_fr && (env->active_fpu.fcr0 & (1 << FCR0_F64)) 48 && !(env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) { 49 /* cannot set FR=0 */ 50 return -TARGET_EOPNOTSUPP; 51 } 52 if (new_fre && !(env->active_fpu.fcr0 & (1 << FCR0_FREP))) { 53 /* Cannot set FRE=1 */ 54 return -TARGET_EOPNOTSUPP; 55 } 56 57 int i; 58 fpr_t *fpr = env->active_fpu.fpr; 59 for (i = 0; i < 32 ; i += 2) { 60 if (!old_fr && new_fr) { 61 fpr[i].w[!FP_ENDIAN_IDX] = fpr[i + 1].w[FP_ENDIAN_IDX]; 62 } else if (old_fr && !new_fr) { 63 fpr[i + 1].w[FP_ENDIAN_IDX] = fpr[i].w[!FP_ENDIAN_IDX]; 64 } 65 } 66 67 if (new_fr) { 68 env->CP0_Status |= (1 << CP0St_FR); 69 env->hflags |= MIPS_HFLAG_F64; 70 } else { 71 env->CP0_Status &= ~(1 << CP0St_FR); 72 env->hflags &= ~MIPS_HFLAG_F64; 73 } 74 if (new_fre) { 75 env->CP0_Config5 |= (1 << CP0C5_FRE); 76 if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) { 77 env->hflags |= MIPS_HFLAG_FRE; 78 } 79 } else { 80 env->CP0_Config5 &= ~(1 << CP0C5_FRE); 81 env->hflags &= ~MIPS_HFLAG_FRE; 82 } 83 84 return 0; 85 } 86 #define do_prctl_set_fp_mode do_prctl_set_fp_mode 87 88 #endif /* MIPS_TARGET_PRCTL_H */ 89