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