Skip to content

Commit 64ea3d6

Browse files
Stefan MarkovicAMarkovic
Stefan Markovic
authored andcommittedOct 29, 2018
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: Aleksandar Markovic <[email protected]> Signed-off-by: Stefan Markovic <[email protected]>
1 parent 0c1bbed commit 64ea3d6

File tree

3 files changed

+62
-4
lines changed

3 files changed

+62
-4
lines changed
 

‎linux-user/mips/target_syscall.h

+2
Original file line numberDiff line numberDiff line change
@@ -247,5 +247,7 @@ static inline abi_ulong target_shmlba(CPUMIPSState *env)
247247
/* MIPS-specific prctl() options */
248248
#define TARGET_PR_SET_FP_MODE 45
249249
#define TARGET_PR_GET_FP_MODE 46
250+
#define TARGET_PR_FP_MODE_FR (1 << 0)
251+
#define TARGET_PR_FP_MODE_FRE (1 << 1)
250252

251253
#endif /* MIPS_TARGET_SYSCALL_H */

‎linux-user/mips64/target_syscall.h

+2
Original file line numberDiff line numberDiff line change
@@ -244,5 +244,7 @@ static inline abi_ulong target_shmlba(CPUMIPSState *env)
244244
/* MIPS-specific prctl() options */
245245
#define TARGET_PR_SET_FP_MODE 45
246246
#define TARGET_PR_GET_FP_MODE 46
247+
#define TARGET_PR_FP_MODE_FR (1 << 0)
248+
#define TARGET_PR_FP_MODE_FRE (1 << 1)
247249

248250
#endif /* MIPS64_TARGET_SYSCALL_H */

‎linux-user/syscall.c

+58-4
Original file line numberDiff line numberDiff line change
@@ -9529,11 +9529,65 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
95299529
#endif
95309530
#ifdef TARGET_MIPS
95319531
case TARGET_PR_GET_FP_MODE:
9532-
/* TODO: Implement TARGET_PR_SET_FP_MODE handling.*/
9533-
return -TARGET_EINVAL;
9532+
{
9533+
CPUMIPSState *env = ((CPUMIPSState *)cpu_env);
9534+
ret = 0;
9535+
if (env->CP0_Status & (1 << CP0St_FR)) {
9536+
ret |= TARGET_PR_FP_MODE_FR;
9537+
}
9538+
if (env->CP0_Config5 & (1 << CP0C5_FRE)) {
9539+
ret |= TARGET_PR_FP_MODE_FRE;
9540+
}
9541+
return ret;
9542+
}
95349543
case TARGET_PR_SET_FP_MODE:
9535-
/* TODO: Implement TARGET_PR_GET_FP_MODE handling.*/
9536-
return -TARGET_EINVAL;
9544+
{
9545+
CPUMIPSState *env = ((CPUMIPSState *)cpu_env);
9546+
bool old_fr = env->CP0_Status & (1 << CP0St_FR);
9547+
bool new_fr = arg2 & TARGET_PR_FP_MODE_FR;
9548+
bool new_fre = arg2 & TARGET_PR_FP_MODE_FRE;
9549+
9550+
if (new_fr && !(env->active_fpu.fcr0 & (1 << FCR0_F64))) {
9551+
/* FR1 is not supported */
9552+
return -TARGET_EOPNOTSUPP;
9553+
}
9554+
if (!new_fr && (env->active_fpu.fcr0 & (1 << FCR0_F64))
9555+
&& !(env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) {
9556+
/* cannot set FR=0 */
9557+
return -TARGET_EOPNOTSUPP;
9558+
}
9559+
if (new_fre && !(env->active_fpu.fcr0 & (1 << FCR0_FREP))) {
9560+
/* Cannot set FRE=1 */
9561+
return -TARGET_EOPNOTSUPP;
9562+
}
9563+
9564+
int i;
9565+
fpr_t *fpr = env->active_fpu.fpr;
9566+
for (i = 0; i < 32 ; i += 2) {
9567+
if (!old_fr && new_fr) {
9568+
fpr[i].w[!FP_ENDIAN_IDX] = fpr[i + 1].w[FP_ENDIAN_IDX];
9569+
} else if (old_fr && !new_fr) {
9570+
fpr[i + 1].w[FP_ENDIAN_IDX] = fpr[i].w[!FP_ENDIAN_IDX];
9571+
}
9572+
}
9573+
9574+
if (new_fr) {
9575+
env->CP0_Status |= (1 << CP0St_FR);
9576+
env->hflags |= MIPS_HFLAG_F64;
9577+
} else {
9578+
env->CP0_Status &= ~(1 << CP0St_FR);
9579+
}
9580+
if (new_fre) {
9581+
env->CP0_Config5 |= (1 << CP0C5_FRE);
9582+
if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
9583+
env->hflags |= MIPS_HFLAG_FRE;
9584+
}
9585+
} else {
9586+
env->CP0_Config5 &= ~(1 << CP0C5_FRE);
9587+
}
9588+
9589+
return 0;
9590+
}
95379591
#endif /* MIPS */
95389592
#ifdef TARGET_AARCH64
95399593
case TARGET_PR_SVE_SET_VL:

0 commit comments

Comments
 (0)
Please sign in to comment.